求和为指定数字的连续正整数数列
2012-01-09 00:00
239 查看
比如 sn = 100 时,总和为100 的连续正整数数列有
对于这种算法的设计,我们最容易想到的就是从 1 到 sn 循环遍历所有的数,对于每个数再循环计算是否以这个数为起点总和正好是sn。这种算法的时间复杂度大概是O(n*log2n), 也就是说如果这样计算,当 sn = 100万时,大概需要循环 2000万次左右。 这样做效率自然是比较低的。那么我们有没有比上述方法更高效的方法呢?答案是肯定的。
首先我们看等差数列求和的公式:Sn=n(a1+an)/2=na1+n(n-1)/2
从这个公式我们不难看出当 Sn 和 n 固定时求a1 是一个线性函数:a1 = (Sn – n(n-1)/2) / n
有了这个函数,优化这个算法就很简单了,我们只要把 n 从 1 开始遍历,一直遍历到 (Sn – n(n-1)/2) < n 为止,就可以找到所有的符合条件的连续数列了,这个算法的算法复杂度为 2N 的平方根,也就是说当 Sn = 100 万时,只需要循环1414次就可以得到所有的数列。
题目:在1~500这500个整数中,找出连续相加等于500的数?
简要分析:int[] X={1,2,i,…………499}
条件是:i+(i+1)+ ……+(i+k)=500 (1式)
运用等差数列求和公式:(k+1)*i+(k+1)*k/2=500 (2式)
其中i和k还有一个隐藏关系i*k<500 (3式)
于是很自然得到如下解法:
得出结果:
这个算法 sn = 100 万时,循环次数是 12970034 次,比之前说的算法效率上要低将近1万倍。
下面给出差点的算法代码
100 18 19 20 21 22 9 10 11 12 13 14 15 16
对于这种算法的设计,我们最容易想到的就是从 1 到 sn 循环遍历所有的数,对于每个数再循环计算是否以这个数为起点总和正好是sn。这种算法的时间复杂度大概是O(n*log2n), 也就是说如果这样计算,当 sn = 100万时,大概需要循环 2000万次左右。 这样做效率自然是比较低的。那么我们有没有比上述方法更高效的方法呢?答案是肯定的。
首先我们看等差数列求和的公式:Sn=n(a1+an)/2=na1+n(n-1)/2
从这个公式我们不难看出当 Sn 和 n 固定时求a1 是一个线性函数:a1 = (Sn – n(n-1)/2) / n
有了这个函数,优化这个算法就很简单了,我们只要把 n 从 1 开始遍历,一直遍历到 (Sn – n(n-1)/2) < n 为止,就可以找到所有的符合条件的连续数列了,这个算法的算法复杂度为 2N 的平方根,也就是说当 Sn = 100 万时,只需要循环1414次就可以得到所有的数列。
题目:在1~500这500个整数中,找出连续相加等于500的数?
简要分析:int[] X={1,2,i,…………499}
条件是:i+(i+1)+ ……+(i+k)=500 (1式)
运用等差数列求和公式:(k+1)*i+(k+1)*k/2=500 (2式)
其中i和k还有一个隐藏关系i*k<500 (3式)
于是很自然得到如下解法:
private static void GetSomeInt(int maxInt) { for (int i = 1; i < (maxInt - 1); i++) { for (int k = 1; k < (maxInt / i); k++) { if (((k + 1) * i + k * (k + 1) / 2) == maxInt) { /*******************输出结果集*********************/ string result = "xi="; for (int s = 0; s < (k + 1); s++) { result += (i + s).ToString() + ";"; } result = result.TrimEnd(';'); Console.WriteLine(result); /************************************************/ } } } }
得出结果:
xi=8;9;10;11;12;13;14;15;16;17;18;19;20;21;22;23;24;25;26;27;28;29;30;31;32 xi=59;60;61;62;63;64;65;66 xi=98;99;100;101;102
这个算法 sn = 100 万时,循环次数是 12970034 次,比之前说的算法效率上要低将近1万倍。
下面给出差点的算法代码
static void ListSequence(int sn) { //忽略 sn 不是正整数的情况 if (sn <= 0) { return; } int n = 1; //n 从1 开始遍历 int m = sn - n * (n - 1) / 2; //m 为 Sn – n(n-1)/2 while (m >= n) //当m < n 时即 Sn – n(n-1)/2 < n 时退出循环 { if (m % n == 0) //如果m 可以被 n 整除,则存在连续n个正整数序列总和为sn。 { int a1 = m / n; //求a1 //打印符合条件的连续数列 for (int i = a1; i < a1 + n; i++) { Console.Write(string.Format("{0} ", i)); } Console.WriteLine(); } n++; //n 加1 m = sn - n * (n - 1) / 2; //下一个 m } Console.WriteLine("循环次数:{0}", n); }
相关文章推荐
- 求和为S的所有连续正数数列
- 求和为指定数字的所有组合
- hdu 5086 数列连续和求和
- hdu 5086 数列连续和求和
- 寻找和为给定数的连续正整数数列
- 数组求和为指定数字
- 笔试题:输入两个正整数a和b,然后分别将他们的数字按照高位在右边的 方式反转后求和!
- 关于连续数字求和组合问题。
- 笔试题:求和为sum的连续数列
- 如何高效的找到所有总和为 sn 的连续正整数数列。
- 运用求和公式拆分连续正整数之和
- 计算和为给定数的连续正整数数列
- 谷歌笔试题--给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。
- Python算法题----求出和为S的所有连续正整数数列
- 一个有序数组数组,给出和为s的两个数字和连续正数数列
- 谷歌笔试题--给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。
- 谷歌笔试题--给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。
- 判断一个正整数是否可以由连续正整数求和而来
- 【BAT经典算法面试题系列】求和为n的连续正整数
- 给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。