输出和为n的所有的连续自然数序列
输出和为n的所有的连续自然数序列
如 n = 9:
9
4 5
2 3 4
《编程之美》的题目(2.21只考加法的面试题),去年曾经写过本题的代码,后来不知道把代码放哪里了。按以前的思路,重写了下代码,写完后翻了下书,结果发现与书上要求的还不一样。
假设,拆分成的数列为:m, m+1, … m+k-1
则 n = (m + m + k - 1) * k / 2 或 2*n = (2*m + k - 1) * k
显然就是求2*n的所有因子,最简单的方法就是暴力搜索:
对公式2*n = (2*m + k - 1) * k 进行转变,可得下面几种方法:
方法一:
2*m + k – 1 = 2 * n / k
从k = 1 开始判断 k 是否是 2 * n的因子,当 k > 2 * n / k 时终止
(由于2*m + k – 1和 k奇偶性相反,输出结果前还要判断k与2 * n / k是否奇偶性相反)
循环次数约为:sqrt(2*n)
方法二:
m = (n – k * (k - 1) / 2) / k > 0
从k = 1 开始判断 k 是否是(n – k * (k - 1) / 2)的因子,当m <= 0时终止
循环次数约为:sqrt(2*n)
上面两种方法,效率相差不大,并且都不高,对 n = 2^30,这种不能拆分的数,要进行大量的计算。注意到2*m + k – 1和 k奇偶性相反,可以先将2 * n的所有质因子2提取出来,假设总共有t个2,则 2 * n = 2^t * nn(nn为奇数),问题转为求nn的所有因子,假设nn = a * b (a <= b),由于 2 * m + k – 1 一定大于k,由2 * n = 2^t * a * b可得两组2*n的两组因子(2^t * a, b) 和 (a, 2^t * b) 这两组数中,较小的那个就是k。采用这种方法的好处是,对偶数能极大的减少计算,特别是对n = 2^30,可以不进行任何除法计算。
对 nn求因子,可以采用上面的方法一和方法二,于是得到方法三和方法四。
方法三:
2 * n = 2^t * nn 奇数 nn = i * j (i <= j) -> j = nn / i
从i = 1开始(每次递增2),判断i是否是nn的因子,当 j > i 时终止。
循环次数约为:sqrt(nn) / 2
方法四:
2 * n = 2^t * nn 奇数 nn = i * (i + j) (j >= 0) -> j = (nn – i * i) / i >= 0
从i = 1开始(每次递增2),判断i是否是(nn – i * i) / i的因子,当 j < 0时终止。
循环次数约为:sqrt(nn) / 2
方法五:
既然是求所有的因子,那么最好的方法当然是利用质因子进行组合。
下面的代码存在一些需要优化的地方,比如存在重复计算、防止编译器对n / i 和n % i进行两次除法计算。如果数不是太大,可以缓存所有的质因子。
另见: 输出自然数n的所有因子。
(下面的代码,要将函数参数改为unsigned的话,需要将i=1的情况单独列出来讨论,即可保证计算过程中不会发生溢出。)
void output(int beg, int len) { printf("%d-%d\n", beg, beg + len - 1); }
inline void output2(int i, int j) { output((i - j + 1) / 2u, j); }
//方法三
void seq3(int n)
{ //2*n = (2*m+k-1)*k //m, m+1, ... m+k-1
if (n <= 0) return; //
unsigned count = 1;
while (n % 2u == 0) { n /= 2u; ++count; } //去除质因子2,设f = 2^x
for (unsigned i = 1; ;i += 2) { //获取nn的所有因子 nn = i * j 且 i <= j
unsigned j = n / i;
if (i > j) break;
if (n % i) continue;
output2(j << count, i); //k=i 2m+k-1=j*2*f
if (i == j) break;
unsigned t = i << count;
if (t > j) output2(t, j);
else output2(j, t);
}
printf("\n");
}
//方法四
void seq4(int n)
{ //2*n = (2*m+k-1)*k //m, m+1, ... m+k-1
if (n <= 0) return; //
unsigned count = 1;
while (n % 2u == 0) { n /= 2u; ++count; } //去除质因子2,设f = 2^x
n -= 1 * 1;
for (unsigned i = 1; n >= 0; n -= 4 * i + 4, i += 2) { //获取nn的所有因子
if (n % i == 0) { // nn = (i+a)*i -> a = (nn - i * i) / i
unsigned j = n / i + i;
output2(j << count, i); //k=i 2m+k-1=j*2*f
if (i == j) continue;
unsigned t = i << count;
if (t > j) output2(t, j);
else output2(j, t);
}
}
printf("\n");
}
//方法五
unsigned gn = 0; //值为 2 * n
static void factor(unsigned n, unsigned k = 1, unsigned beg = 3)
{
assert(n & 1);
assert(beg & 1);
if (n == 1) {
unsigned t = ::gn / k;
if (t > k) output2(t, k);
else output2(k, t);
return;
}
assert(n >= beg);
for (unsigned i = beg, count = 0; ;i += 2) {
//if (n % i) {
// if (n / i >= i) continue;
// factor(1, k, n); // n是质数
// factor(1, k * n, n);
// return;
//}
if (i > n / i) {
factor(1, k); // n是质数,
factor(1, k * n);
return;
}
if (n % i) continue;
++count;
n /= i;
while (n % i == 0) { ++count; n /= i; }
for (unsigned j = 0, f = k; j <= count; ++j, f *= i)
factor(n, f, i + 2);
return;
}
}
void seq(int n)
{ //2*n = (2*m+k-1)*k //m, m+1, ... m+k-1
if (n <= 0) return;
::gn = n * 2u;
while (n % 2u == 0) { n /= 2u;} //去除质因子2
factor(n);
printf("\n");
}
转载于:https://www.cnblogs.com/flyinghearts/archive/2011/03/22/1992003.html
输出和为n的所有的连续自然数序列相关推荐
- 编程笔试(解析及代码实现):求和为N的正整数序列之实现一个函数,输入为一个正整数N (比如100),输出为所有和等于N的[连续]正整数序列
编程笔试(解析及代码实现):求和为N的正整数序列之实现一个函数,输入为一个正整数N (比如100),输出为所有和等于N的[连续]正整数序列 目录 题目描述 代码实现 题目描述 求和为N的正整数序列:实 ...
- 最长递增子序列 最长连续递增序列
引言 这两道题有很大的相似性,在这里主要的地方就是循环的设置,不仅仅适用于这两道题,在很多类似的题目中都可以用到,要学会相应的方法才行: 最长递增子序列 给你一个整数数组 nums ,找到其中最长严格 ...
- 【枚举】连续自然数和(jzoj 2102)
连续自然数和 题目大意: 输出一个n,求出所有相加等于n的连续自然数序列 样例输入 10000 样例输出 18 142 297 328 388 412 1998 2002 数据范围限制 10 < ...
- leetcode 674. 最长连续递增序列
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度. 连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都 ...
- 【实习笔试面试题】2013网易互联网实习笔试算法题-找出最大连续自然数个数
找出最大连续自然数个数 搜集者:江南烟雨 E-Mail:xiajunhust@gmail.com 本题为网易互联网暑期实习生笔试算法题. 凭记忆记录下来的题目,如违反网易版权请邮件联系,本人会删除. ...
- leetcode--最长连续递增序列--python
文章目录 题目 题目详情 示例 解题思路 思路 代码 运行结果 最佳方案 题目 题目详情 给定一个未经排序的整数数组,找到最长且连续的的递增序列. 示例 输入: [1,3,5,4,7] 输出: 3 解 ...
- 和为s的连续正数序列
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数). 序列内的数字由小到大排列,不同序列按照首个数字从小到大排列. 示例 1: 输入:target = 9 ...
- 41.和为s的两个数字 VS 和为s的连续正数序列
为什么80%的码农都做不了架构师?>>> 题目一:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s.如果有多对数字的和等于s,输出任意一对即可. ...
- 和为s的两个数字与和为s的连续正数序列
题目一:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s.如果有多对数字的和等于s,则输出任意一对即可. 分析:选择数组的两端,将其相加,然后与s比较,如果比s大,则将指向 ...
最新文章
- 独家解读 | 滴滴机器学习平台架构演进之路
- ASP.NET Core中使用GraphQL - 第一章 Hello World
- 上海交通大学2006年各学院本科生平均薪酬统计
- Eclipse 3.2 + Tomcat 5.5 + Lomboz 3.2 简单配置
- 网红奶茶雪糕高价背后,到底是真好吃还是智商税
- 魅族管理层换血?官方回应:信息被错误解读 黄章仍为最大股东
- iscsi-target
- 利用c语言面向对象编程,用C语言程序实现面向对象编程
- 解读2016之Golang篇:极速提升,逐步超越
- App调试内存泄露之Context篇(下)-App调试内存泄露之Context篇(下)
- QQ能上网页打不开解决办法
- matlab中ode45如何设置,如何使用Matlab中的ode45修正赋值错误(ode45函数的第488行)
- Multisim仿真—CMOS门电路
- AdSense后台添加美国税务信息W-8BEN纳税表秒过的详细操作图文教程
- 华为数字化转型之道第二讲
- 智能家居系统解决方案
- pRRophetic 通过基因表达水平预测临床化疗反应的R包
- jQuery UI Datepicker 选择时分秒
- UNI-APP_HbuilderX打包出错,本次打包选择了通讯录权限,请完成实名认证后再继续打包,取消通讯录权限打钩,还是提示使用通讯录权限需要实名制
- Ngrok的注册使用
热门文章
- hashcode 和 equals 的关系_Java equals 和 hashCode 的这几个问题可以说明白吗?
- mysql @@version_MySQL数据库安装Version5.5
- 天翼云从业认证(4.11)天翼云物流行业解决方案
- 【分享】老调重弹,既懂技术又懂管理的人才发展中的实际问题
- 【项目管理】进度管理
- 实现图片验证码,其实就是简单的验证码实现,记录一下
- Python入门教程以及资料免费下载
- EasyUI中Tabs标签页的简单使用
- Xcode8上传成功后,商店里构建版本却没有应用
- c语言十六进制的输出与站位,运算符与格式输出输入4