题目重现
一个正整数N的因子中可能存在若干连续的数字。例如630
可以分解为3*5*6*7
,其中5、6、7就是3个连续的数字。给定任一正整数N,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列。
输入格式
输入在一行中给出一个正整数 N(1<N<231) 。
输出格式
首先在第1行输出最长连续因子的个数;然后在第2行中按“因子1*因子2*……*因子k
”的格式输出最小的连续因子序列,其中因子按递增顺序输出,1不算在内。
输入样例
630
输出样例
3
5*6*7
题解
直接从2开始枚举连续因子序列的起点即可。
由于是连续的,只需要记录连续因子序列的起点与终点即可。
product(start,end)=∏i=startendi
根据题意要求:
product(start,end)|N
符合要求的 start, end 有若干对,要求出其中长度(end - start)最长,其次起点(start)最小。
answerCandidates.reduce((pre, cur) => {
if (cur.end - cur.start > pre.end - pre.start) return cur;
if (cur.end - cur.start < pre.end - pre.start) return pre;
if (cur.start < pre.start) return cur;
return pre;
}, {
start: N,
end: N
});
这种将多个元素转化成一个元素的抽象做法称为 Reduce,典型的例子有:求和、求最值、状态更新等。
特征是“有损的信息聚合”。
性能
- 枚举连续因子序列起点 start∈[2,⌈N−−√⌉] ,如果使用 [2,N] 将会直接超时,因为N很大。
- 从 start 开始迭代终点 end ,碰到第一个不能整除的就结束迭代,此时 end 不能计入答案序列,因此是左开右闭区间。
- 迭代过程中,要拷贝一个N,每次迭代用 end 除它,不需要在每次迭代中计算一个连续积。
时间复杂度: O(N−−√Factorial−1(N))
Factorial 是阶乘函数,其反函数在 [2,231) 上的值域为 [2,12] 可以近似看成常数。
需要注意的测试样例
2147483647
即INT_MAX
,有上溢的危险。
至少有3种方法可以解决这个问题:
- 可以使用
long long
- 加特殊判断
- 使用闭区间描述起点、终点
但总的来说,使用闭区间很难保证程序简洁易懂。
在计算机程序中,我们经常使用左闭右开区间去描述一个序列。