Medium级别的题:给定正整数n和k,满足1<=k<=n<=1000,求n的第k大的约数,如果n的约数个数少于k,返回-1。
例如:输入n = 12, k = 3返回3
因为12的约数从小到大分别为{1, 2, 3, 4, 6, 12}
又如:输入n = 4, k = 4返回-1
因为4只有1, 2, 4这3个约数。
分析:无聊题。不知道考点在哪,这么小的数据范围。
方法1 暴力
线性枚举,由小到大枚举约数。
代码:
class Solution {public: int kthFactor(int n, int k) { for (int i = 1; i <= n; ++i) { if (n % i == 0 && --k == 0) return i; } return -1; }};
方法2 sqrt(n)枚举n的约数,再排序
代码:
class Solution {public: int kthFactor(int n, int k) { vector<int> v; for (int i = 1; i * i <= n; ++i) { if (n % i == 0) { v.push_back(i); if (n / i != i) { v.push_back(n / i); } } } if (v.size() < k) return -1; sort(v.begin(), v.end()); return v[k - 1]; }};
方法3 可以考虑把n,分解质因数,因为2 * 3 * 5 * 7 * 11 = 2310,所以n <= 1000时,它最多有4个不同的质因数。然后利用“丑数”的方法,从小到大枚举只由这些质因数相乘组成的数——但是要注意,不是n的约数的要跳过。
代码(略长):
class Solution {public: int kthFactor(int n, int k) { if (k == 1) return 1; vector<int> v; int m = n; for (int i = 2; i * i <= m; ++i) { if (n % i == 0) { v.push_back(i); while (m % i == 0) { m /= i; } } } if (m > 1) v.push_back(m); vector<int> f = {1}; vector<int> ind(v.size()); while (f.size() < k) { bool out = true; int temp = n + 1; for (int i = 0; i < v.size(); ++i) { while (ind[i] < f.size() && n % (f[ind[i]] * v[i])) { ++ind[i]; } if (ind[i] < f.size()) { temp = min(temp, f[ind[i]] * v[i]); out = false; } } if (out) return -1; for (int i = 0; i < v.size(); ++i) { if (ind[i] < f.size()) { const int may = f[ind[i]] * v[i]; if (n % may == 0) { if (may == temp) ++ind[i]; } } } if (temp <= n) f.push_back(temp); } return f[k - 1]; }};