【劍指offer】和爲定值的連續正數序列

轉載請註明出處:http://blog.csdn.net/ns_code/article/details/27823291

題目描述:

小明很喜歡數學,有一天他在做數學作業時,要求計算出9~16的和,他馬上就寫出了正確答案是100。但是他並不滿足於此,他在想究竟有多少種連續的正數序列的和爲100(至少包括兩個數)。沒多久,他就得到另一組連續正數和爲100的序列:18,19,20,21,22。現在把問題交給你,你能不能也很快的找出所有和爲S的連續正數序列? Good Luck!

輸入:

輸入有多組數據。

每組數據僅包括1個整數S(S<=1,000,000)。如果S爲負數時,則結束輸入。

輸出:

對應每組數據,若不存在和爲S的連續正數序列,則輸出“Pity!”;否則,按照開始數字從小到大的順序,輸出所有和爲S的連續正數序列。每組數據末尾以“#”號結束。

樣例輸入:
4
5
100
-1
樣例輸出:
Pity!
#
2 3
#
9 10 11 12 13 14 15 16
18 19 20 21 22
#
    這道題剛開始用的劍指offer上的思路寫的代碼,我也是同樣將打印正數序列部分的代碼獨立開來寫成了一個函數,但是在九度OJ上測試,最後一個測試用例超時了,看論壇很多人採取此策略也都AC了,知識最後一個測試用例的時間可能要400ms左右,我就覺得應該是調用打印函數耗費了太多時間,尤其連續序列有很多的時候,要很多次地調用,開銷還是蠻大的。就把打印部分的代碼和尋找連續序列的代碼寫在了一起,這次AC了,最後一個測試用例的時間是340ms。

    AC代碼如下:

#include<stdio.h>
#include<stdbool.h>
bool can;

/*
void PrintSequence(int start ,int end)
{
	int i;
	for(i=start;i<=end;i++)
	{
		printf("%d",i);
		if(i == end)
			printf("\n");
		else
			printf(" ");
	}
}
*/

/*
找到和爲s的連續正數序列
*/
void FindSumSequence(int s)
{
	int start = 1;
	int end = 2;
	int mid = (1+s)>>1;
	int cursum = start + end;

	while(start < mid)
	{
		if(cursum == s)
		{	can = true;
		//	PrintSequence(start,end);
			int i;
			for(i=start;i<=end;i++)
			{
				printf("%d",i);
				if(i == end)
					printf("\n");
				else
					printf(" ");
			}
			end++;
			cursum += end;
		}
		else if(cursum < s)
		{
			end++;
			cursum += end;
		}
		else
		{
			cursum -= start;
			start++;
		}
	}
}

int main()
{
	int s;
	while(scanf("%d",&s) != EOF && s>=0)
	{
		can = false;
		FindSumSequence(s);
		if(!can)
			printf("Pity!\n");
		printf("#\n");
	}
	return 0;
}
/**************************************************************
    Problem: 1354
    User: mmc_maodun
    Language: C
    Result: Accepted
    Time:380 ms
    Memory:912 kb
****************************************************************/
    另外,九度在這個問題的討論裏面,有個內科大的哥們給了個不錯的解法(我咋就想不出尼,哎!差距啊!!),大致思路如下(慢慢琢磨吧,不難理解,直接從論壇Copy過來的):

S = ( a0 + aN)N/2 ---- 等差數列求和公式
   = ( 2a0-1 + N )N /2

==>  2a0 = 2S/N - N + 1
==>  2S % N == 0 && N < sqrt(2S)

for N =  [ 2 , sqrt(2S) )
      if 2S % N == 0 && 2a0 % 2 == 0
            show( a0 , N )

    我也用這種思路寫了代碼,同樣AC了,不過比劍指offer上的思路寫的代碼要快很多,最後一個測試用例只用了80ms。

    AC代碼如下;

#include<stdio.h>
#include<math.h>
#include<stdbool.h>
bool can;

/*
打印從Start開始的連續n個正數序列
*/
void PrintSequence(int start ,int n)
{
	int i;
	for(i=0;i<n;i++)
	{
		printf("%d",start+i);
		if(i == n-1)
			printf("\n");
		else
			printf(" ");
	}
}

/*
找到和爲s的連續正數序列
*/
void FindSumSequence(int s)
{
	int i;
	//這裏的i爲要求的連續正數的個數,至少爲2
	for(i=(int)sqrt(2*s);i>=2;i--)
	{
		if((2*s)%i == 0)
		{
			int DoubleStart = 2*s/i-i+1;
			if((DoubleStart&1) == 0)	//如果爲偶數
			{
				can = true;
				PrintSequence(DoubleStart/2,i);
			}
		}
	}
}

int main()
{
	int s;
	while(scanf("%d",&s) != EOF && s>=0)
	{
		can = false;
		FindSumSequence(s);
		if(!can)
			printf("Pity!\n");
		printf("#\n");
	}
	return 0;
}
/**************************************************************
    Problem: 1354
    User: mmc_maodun
    Language: C
    Result: Accepted
    Time:110 ms
    Memory:928 kb
****************************************************************/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章