输出和为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的所有的连续自然数序列相关推荐

  1. 编程笔试(解析及代码实现):求和为N的正整数序列之实现一个函数,输入为一个正整数N (比如100),输出为所有和等于N的[连续]正整数序列

    编程笔试(解析及代码实现):求和为N的正整数序列之实现一个函数,输入为一个正整数N (比如100),输出为所有和等于N的[连续]正整数序列 目录 题目描述 代码实现 题目描述 求和为N的正整数序列:实 ...

  2. 最长递增子序列 最长连续递增序列

    引言 这两道题有很大的相似性,在这里主要的地方就是循环的设置,不仅仅适用于这两道题,在很多类似的题目中都可以用到,要学会相应的方法才行: 最长递增子序列 给你一个整数数组 nums ,找到其中最长严格 ...

  3. 【枚举】连续自然数和(jzoj 2102)

    连续自然数和 题目大意: 输出一个n,求出所有相加等于n的连续自然数序列 样例输入 10000 样例输出 18 142 297 328 388 412 1998 2002 数据范围限制 10 < ...

  4. leetcode 674. 最长连续递增序列

    给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度. 连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都 ...

  5. 【实习笔试面试题】2013网易互联网实习笔试算法题-找出最大连续自然数个数

    找出最大连续自然数个数 搜集者:江南烟雨 E-Mail:xiajunhust@gmail.com 本题为网易互联网暑期实习生笔试算法题. 凭记忆记录下来的题目,如违反网易版权请邮件联系,本人会删除. ...

  6. leetcode--最长连续递增序列--python

    文章目录 题目 题目详情 示例 解题思路 思路 代码 运行结果 最佳方案 题目 题目详情 给定一个未经排序的整数数组,找到最长且连续的的递增序列. 示例 输入: [1,3,5,4,7] 输出: 3 解 ...

  7. 和为s的连续正数序列

    输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数). 序列内的数字由小到大排列,不同序列按照首个数字从小到大排列. 示例 1: 输入:target = 9 ...

  8. 41.和为s的两个数字 VS 和为s的连续正数序列

    为什么80%的码农都做不了架构师?>>>    题目一:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s.如果有多对数字的和等于s,输出任意一对即可.   ...

  9. 和为s的两个数字与和为s的连续正数序列

    题目一:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s.如果有多对数字的和等于s,则输出任意一对即可. 分析:选择数组的两端,将其相加,然后与s比较,如果比s大,则将指向 ...

最新文章

  1. 独家解读 | 滴滴机器学习平台架构演进之路
  2. ASP.NET Core中使用GraphQL - 第一章 Hello World
  3. 上海交通大学2006年各学院本科生平均薪酬统计
  4. Eclipse 3.2 + Tomcat 5.5 + Lomboz 3.2 简单配置
  5. 网红奶茶雪糕高价背后,到底是真好吃还是智商税
  6. 魅族管理层换血?官方回应:信息被错误解读 黄章仍为最大股东
  7. iscsi-target
  8. 利用c语言面向对象编程,用C语言程序实现面向对象编程
  9. 解读2016之Golang篇:极速提升,逐步超越
  10. App调试内存泄露之Context篇(下)-App调试内存泄露之Context篇(下)
  11. QQ能上网页打不开解决办法
  12. matlab中ode45如何设置,如何使用Matlab中的ode45修正赋值错误(ode45函数的第488行)
  13. Multisim仿真—CMOS门电路
  14. AdSense后台添加美国税务信息W-8BEN纳税表秒过的详细操作图文教程
  15. 华为数字化转型之道第二讲
  16. 智能家居系统解决方案
  17. pRRophetic 通过基因表达水平预测临床化疗反应的R包
  18. jQuery UI Datepicker 选择时分秒
  19. UNI-APP_HbuilderX打包出错,本次打包选择了通讯录权限,请完成实名认证后再继续打包,取消通讯录权限打钩,还是提示使用通讯录权限需要实名制
  20. Ngrok的注册使用

热门文章

  1. hashcode 和 equals 的关系_Java equals 和 hashCode 的这几个问题可以说明白吗?
  2. mysql @@version_MySQL数据库安装Version5.5
  3. 天翼云从业认证(4.11)天翼云物流行业解决方案
  4. 【分享】老调重弹,既懂技术又懂管理的人才发展中的实际问题
  5. 【项目管理】进度管理
  6. 实现图片验证码,其实就是简单的验证码实现,记录一下
  7. Python入门教程以及资料免费下载
  8. EasyUI中Tabs标签页的简单使用
  9. Xcode8上传成功后,商店里构建版本却没有应用
  10. c语言十六进制的输出与站位,运算符与格式输出输入4