题目:
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?
思路:
一般的解题方法有暴力法和滑动窗口,这里分享另一种解法,首先观察下图:
由此我们可以判断数S能否由m个连续的正整数组成。
接着我们来看:由于1到
2
S
\sqrt{2S}
2S的和大于S,所以m<=
2
S
\sqrt{2S}
2S,既最多也只能有
2
S
\sqrt{2S}
2S个连续的正整数的和等于S,于是我们从2到
2
S
\sqrt{2S}
2S逐个遍历,计算相应的从1到m的和,通过上图所述的方法检验S能否由m个连续的正整数相加得到,如果可以则将相应的m个正整数存入,否则则继续,一直找到m的最大可能的值
2
S
\sqrt{2S}
2S。
代码:
static bool cmp(vector<int> a,vector<int> b)
{
return a[0]<b[0];
}
vector<vector<int> > FindContinuousSequence(int sum) {
vector<vector<int> > out_v;
int max_n=(int)sqrt(sum*2)+1;
for(int i=1;i<=max_n;i++)
{
int over_sum=(1+i)*i/2;
if(sum<=over_sum)
break;
float start_num=(float)(sum-over_sum)/(float)(i+1);
if((int)start_num>0&&start_num==(int)start_num)
{
vector<int> temp_v;
for(int j=0;j<=i;j++)
temp_v.push_back(j+(int)start_num);
out_v.push_back(temp_v);
}
}
sort(out_v.begin(),out_v.end(),cmp);
return out_v;
}
算法最好情况下是没有连续的正整数符合要求,复杂度是O(
n
\sqrt{n}
n),既只遍历最外层循环;
最坏情况是每个m都有连续的m个正整数符合,复杂度是O(n),既1到
2
n
\sqrt{2n}
2n的和。