每日一道算法题:输出和为n的连续正整数序列

题目:输入一个正数n,输出所有和为n连续正数序列。

例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3个连续序列1-5、4-6和7-8。

解题思路:我们以正数21为例,由于21=1+2+3+4+5+6=6+7+8=10+11,那么题目要求输出的连续序列为1-6、6-8和10-11。假设计算出的某个序列为m-n,那么这个序列中正数的个数为(n-m+1),这里,可以参照高斯求解1+2+3+...+100的思路,所要解的式子为21=(n+m)*(n-m+1)/2。通过从数字1开始遍历,到哪个数停止呢?题目所要求的是连续正整数之和,可以知道正数n至少为两个数之和,并且这两个数必须是连续的,那么,从数字1开始遍历一直到正数n的一半取上限值即可。代码如下:

#include 
using namespace std;

#define N 21

int main(){
    int start = 0;
    int end = 0;
    for (start = 1; start <= N/2+1; start++){
        for (end = start+1; end <= N/2+1; end++){
            if ((start+end) * (end-start+1) == 2 * N){
                cout << "结果为: " << start << "-" << end << endl;
                break;
            }
        }
    }
    system("pause");
    return 0;
}

上面代码的时间复杂度为O(n*n),一般情况下是不会采用上述思路的,那么下面这种类似于游标卡尺的思路在时间复杂度方面表现的更好一些。还是假设计算出的某个序列为m-n,另m=1,n=2,m到n之间的和sum=1,如果m到n之间的和sum等于正数n,输出这个序列;如果和sum小于n,另n继续向右移动,加上更大的数,直到和sum等于n为止;如果和sum大于n,另m向右移动,减去更小的数,直到和sum等于n为止。代码如下:

#include 
using namespace std;

void func(int N){
    if (N<=0){
        return;
    }
    int start = 1;
    int end = 2;
    int count = (N+1)/2;
    int sum = 1;
    while (start <= count){
        if (sum == N){
            cout << "结果为: " << start << "-" << (end-1) << endl;
            sum -= start;
            start++;
        }
        else if (sum < N){
            sum += end;
            end++;
        }
        else{
            sum -= start;
            start++;
        }
    }
}

int main(){
    func(21);
    system("pause");
    return 0;
}



你可能感兴趣的:(数据结构+算法)