题目:给定一个数 n, 1<= n<=10^15,求第k小因子。假设10^8次执行时间为1s。
这道题我相信大家都能够想到O(n)的解决方法,但是考虑到时间复杂度,如果一个数为10^15次方,这将是一个很大的计算时间,因此O(n)不可取。
接下来提供一个 O(n^(1/2))的方法,其实也很简单,就是只遍历 sqrt(n)次,因为因子数是一一对应的(比如24,我们求出了因子3,那么因子8也就能够求出来)。如此下来,我们的计算时间可以控制在1s以内。
思路:
假设 n=24;
用两个数组a、b分别保存小因子数(如 1,2,3,4)和大因子数(24,12,8,6),大因子数可以通过 【n/小因子数】得到。
得出第k小因子与a、b数组元素个数之间的关系,求出最终结果。
注意:
1. 所有的 数用 unsigned long long 数据类型,以防越界;
2. 对于25这种(存在 5*5的情况),不要重复记录因子个数。
以下是源代码:
#include<iostream>
#include<cmath>
using namespace std;
unsigned long long theKFactor(unsigned long long n, int k)
{
unsigned long long a[1000],b[1000],j(0),t(0),count(0);
for (long long int i = 1; i <= sqrt(n); i++) {
if (n % i == 0) {
unsigned long long large = n/i; // i 和 n/i
a[j++] = i; // 数组 a 记录小因子数
if (i != large) b[t++] = large; // 防止重复的因子,数组 b 记录大因子数
count++;
if (k == count) break; // 提前找到,直接退出
}
}
// 此时,j 为数组 a 中因子个数,t为数组 b 中因子个数
if (k <= 0 || k > j + t) return 0; // 不合法的 K, 返回 0
if (k <= j) return a[k-1]; // 小于一半
else return b[t-(k-j)]; // 大于一半
}
int main()
{
unsigned long long max = theKFactor(1000000000000000,256); // 1000000000000000,由此可知其有 256 个因子
cout<<max<<endl;
max = theKFactor(1000000000000000,128); // 31250000
cout<<max<<endl;
max = theKFactor(25,3); // 25,因子 5只能算 1 次
cout<<max<<endl;
max = theKFactor(15,3); // 5
cout<<max<<endl;
max = theKFactor(24,9); // 0,不合法的k
cout<<max<<endl;
return 0;
}
计算结果:
由此发现,时间复杂度大大降低。