一个整数分解为连续正整数之和

今天去面试遇到了遇到了一道比较经典的题目是将一个整数分解为连续正整数之和(一个数字不算),如15可以分解为:

15 = 1 + 2 + 3 + 4 + 5

15 = 4 + 5 + 6

15 = 7 + 8

这道题很明显可以用穷举的方法求出。输入数num,设置起始位置i,再遍历连续正整数的长度k,由公式计算出 sum = i + (i+1) + ... + (i+k) = (k+1) * (2*i + k) / 2,判断与n的关系,若相等则打印出从i到i+k这(k+1)个数;若sum>num,则break;

代码如下:

#include<iostream>
using namespace std;

int main()
{
	int num,sum=0;
	cin>>num;
	for(int i=1;i<=num/2;i++) //两个大于num/2的整数之和肯定大于num,故只需循环到num/2
	{
		for(int k=1;;k++)             //k从1开始,不是从i开始
		{
			sum = (k+1)*(2*i+k)/2;
			if(sum > num)
				break;
			if(sum == num)
			{
				for(int j=0;j<k;j++)
					cout<<i+j<<"+";    //输出i+j
				cout<<i+k<<endl;
			}
		}
	}
	return 0;
}
//时间复杂为O(n^2)


但很明显这算法的复杂度比较高!达到O(n^2)!因此我们需要找到一个更加优化的算法。

由上我们可知从i开始连续k个数之和的计算公式如下:

                          sum = k * (2 * i + k - 1) / 2;

在题目要求sum == num 的所有可能情况,上面的解法是从起始位置开始循环,又根据连续个数循环,这样需要两重循环。但如果我们根据上面的公式逆向想想,如果sum==num时,i与k的关系等式为k * (2 * i + k - 1) = 2 * num。因此,如果用k循环,计算出起始位置 i = ( 2*n / k - k + 1) / 2,岂不是时间复杂度降到线性的了。如下:

#include<iostream>
using namespace std;

int main()
{
	int num,temp;
	cin>>num;
	for(int k=1;k<=num/2;k++)
	{
		//cout<<k<<endl;
		if(2*num % k == 0)   //由公式k * (2 * i + k - 1) = 2 * num知道2 * num能够被k整除
		{
			temp = 2*num/k-k+1;  //k * (2 * i + k - 1) = 2 * num转换成i = ( 2*num / k - k + 1) / 2,【temp=( 2*num / k - k + 1)】
			if(temp%2==0&&temp/2!=0)   //能被2整除且保证第一位不为0
			{
				int i = temp/2;
				for(int j=0;j<k-1;j++)
					cout<<i+j<<"+";
				cout<<i+k-1<<endl;
			}
		}
	}
	return 0;
}
//时间复杂为O(n)


你可能感兴趣的:(一个整数分解为连续正整数之和)