【问题标题】:form a number using consecutive numbers用连续的数字组成一个数字
【发布时间】:2011-02-07 05:32:53
【问题描述】:

我对微软面试中的一个问题感到困惑,如下所示:

一个函数应该接受一个范围(3 - 21),它应该打印所有连续的数字组合以形成每个数字,如下所示:

3 = 1+2 5 = 2+3 6 = 1+2+3 7 = 3+4 9 = 4+5 10 = 1+2+3+4 11 = 5+6 12 = 3+4+5 13 = 6+7 14 = 2+3+4+5 15 = 1+2+3+4+5 17 = 8+9 18 = 5+6+7 19 = 9+10 20 = 2+3+4+5+6 21 = 10+11 21 = 1+2+3+4+5+6

你能帮我在 C# 中形成这个序列吗?

谢谢, 马赫什

【问题讨论】:

  • 到目前为止你做了什么?您是否考虑过递归解决方案?这是显而易见的第一步。或者,您可以研究连续数字之和的性质,并使用它来制定解决方案模式(例如,x 是 3 个连续整数的总和,当且仅当 x 可被 3 整除)。
  • 17=7+8 19=8+9 ???
  • 您是希望报告所有这样的组合(例如 9 = 2+3+4,也一样)还是只报告最短的这样的序列?
  • @Jim Lewis:假设 x 是以 a 开头的 3 个连续整数的总和。那么 x = a + (a+1) + (a+2) = 3a + 3 = 3(a+1),所以它可以被 3 整除。反之,如果 x = 3b 那么 x = (b-1) + b + (b+1)。
  • 我必须补充一点,解决方案模式方法适用于奇数,但对于偶数来说有点痛苦。对问题进行简单的攻击(如下)更有效。

标签: numbers generator


【解决方案1】:

所以这是一个简单/幼稚的答案(在 C++ 中,未经测试;但您应该能够翻译)。它使用的事实是

1 + 2 + ... + n = n(n+1)/2,

你可能以前见过。有很多简单的优化可以在这里进行,为了清楚起见我省略了。


void WriteAsSums (int n)
{
  for (int i = 0; i < n; i++)
  {
    for (int j = i; j < n; j++)
    {
      if (n = (j * (j+1) - i * (i+1))/2) // then n = (i+1) + (i+2) + ... + (j-1) + j
      {
        std::cout << n << " = ";
        for (int k = i + 1; k <= j; k++)
        {
          std::cout << k;
          if (k != j) // this is not the interesting bit
            std::cout << std::endl;
          else
            std::cout << " + ";
        }
      }
    }
  }
}

【讨论】:

    【解决方案2】:

    这是一些伪代码,用于查找所有组合(如果存在):

    function consecutive_numbers(n, m)
        list = [] // empty list
        list.push_back(m)
        while m != n
            if m > n
                first = list.remove_first
                m -= first
            else
                last = list.last_element
                if last <= 1
                    return [] 
                end
                list.push_back(last - 1) 
                m += last - 1
            end
        end
        return list
    end
    
    function all_consecutive_numbers(n)
        m = n / 2 + 1
        a = consecutive_numbers(n, m)
        while a != []
            print_combination(n, a)
            m = a.first - 1
            a = consecutive_numbers(n, m)
        end
    end
    
    function print_combination(n, a)
        print(n + " = ")
        print(a.remove_first)
        foreach element in a
            print(" + " + element)
        end
        print("\n")
    end
    

    调用 all_consecutive_numbers(21) 将打印:

    21 = 11 + 10
    21 = 8 + 7 + 6
    21 = 6 + 5 + 4 + 3 + 2 + 1
    

    我在 ruby​​(代码 here)中对其进行了测试,它似乎可以工作。我确信基本思想也可以很容易地在 C# 中实现。

    【讨论】:

      【解决方案3】:

      我喜欢这个问题。这是一个巧妙且略显神秘的 O(n) 解决方案:

      void DisplaySum (int n, int a, int b)
      {
        std::cout << n << " = ";
        for (int i = a; i < b; i++) std::cout << i << " + ";
        std::cout << b;
      }
      
      void WriteAsSums (int n)
      {
        N = 2*n;
      
        for (int i = 1; i < N; i++)
        {
          if (~(N%i))
          {
            int j = N/i;
            if (j+i%2)
            {
              int a = (j+i-1)/2;
              int b = (j-i+1)/2;
              if (a>0 & a<b) // exclude trivial & negative solutions
                DisplaySum(n,a,b);
            }
          }
        }
      }
      

      【讨论】:

      • 其实我们只需要检查i
      【解决方案4】:

      这是 Groovy 中的一些东西,你应该能够理解发生了什么。它不是最有效的代码,并且不会按照您在问题中引用的顺序创建答案(尽管您似乎遗漏了一些),但它可能会给您一个开始。

      def f(a,b) {
      
        for (i in a..b) {
      
          for (j in 1..i/2) {
      
            def (sum, str, k) = [ 0, "", j ]
      
            while (sum < i) {
              sum += k
              str += "+$k"
              k++
            }
      
            if (sum == i) println "$i=${str[1..-1]}"
           }
        }
      }
      

      f(3,21) 的输出是:

      3=1+2
      5=2+3
      6=1+2+3
      7=3+4
      9=2+3+4
      9=4+5
      10=1+2+3+4
      11=5+6
      12=3+4+5
      13=6+7
      14=2+3+4+5
      15=1+2+3+4+5
      15=4+5+6
      15=7+8
      17=8+9
      18=3+4+5+6
      18=5+6+7
      19=9+10
      20=2+3+4+5+6
      21=1+2+3+4+5+6
      21=6+7+8
      21=10+11
      

      希望这会有所帮助。它有点符合做最简单的事情的原则。

      【讨论】:

        【解决方案5】:

        如果我们将 a 分成 2 位,那么 a = b + (b+1) = 2*b + (0+1)
        如果我们将 a 切成 3 位数,则 a = b + (b+1) + (b+2) = 3*b + (0+1+2)
        ...
        如果我们将 a 切成 n 位,那么 a = b + (b+1) +...+ (b+n) = nb + (0+1+n-1)
        最后的结果是 a = n
        b + n*(n-1)/2,a,b,n 都是整数。
        所以 O(N) 算法是:

        void seq_sum(int a)
        {
        // start from 2 digits
           int n=2;
           while(1)
           {
              int value = a-n*(n-1)/2;
              if(value < 0)
                 break;
        // meet the quotation we deduct
              if( value%n == 0 )
              {
                   int b=value/n;
        // omit the print stage
                   print("......");
              }
              n++;
           }
        }
        

        【讨论】:

          猜你喜欢
          • 2021-06-04
          • 2011-04-08
          • 2022-11-24
          • 2023-03-21
          • 2021-05-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-16
          相关资源
          最近更新 更多