使用连续数字形成一个数字

时间:2010-04-12 22:44:52

标签: numbers generator

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

一个函数应该接受一个范围(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#中形成这个序列吗?

谢谢, 马赫什

5 个答案:

答案 0 :(得分:5)

所以这是一个直截了当/天真的答案(在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 << " + ";
        }
      }
    }
  }
}

答案 1 :(得分:1)

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

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#中实现。

答案 2 :(得分:0)

这是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

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

答案 3 :(得分:0)

我喜欢这个问题。这是一个光滑而略带神秘的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);
      }
    }
  }
}

答案 4 :(得分:0)

如果我们将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)= n b +(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++;
   }
}