**输入:** n = 7, k = 2
**输出:** 7
**解释:** 因子列表包括 [1, 7] ,第 2 个因子是 7 。
示例 3:
**输入:** n = 4, k = 4
**输出:** -1
**解释:** 因子列表包括 [1, 2, 4] ,只有 3 个因子,所以我们应该返回 -1 。
提示:
1 <= k <= n <= 1000
进阶:
你可以设计时间复杂度小于 O(n) 的算法来解决此问题吗?
方法一:枚举
我们可以从小到大枚举所有在 [1, n] 范围内的数,并判断是否为 n 的因子。
[sol1-C++]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution { public: intkthFactor(int n, int k){ int count = 0; for (int factor = 1; factor <= n; ++factor) { if (n % factor == 0) { ++count; if (count == k) { return factor; } } } return-1; } };
[sol1-Java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution { publicintkthFactor(int n, int k) { intcount=0; for (intfactor=1; factor <= n; ++factor) { if (n % factor == 0) { ++count; if (count == k) { return factor; } } } return -1; } }
[sol1-Python3]
1 2 3 4 5 6 7 8 9
classSolution: defkthFactor(self, n: int, k: int) -> int: count = 0 for factor inrange(1, n+1): if n % factor == 0: count += 1 if count == k: return factor return -1
复杂度分析
时间复杂度:O(n)。
空间复杂度:O(1)。
方法二:枚举优化
方法一中的枚举时间复杂度较高,直观地来说,如果 n=1000,那么从 501 开始到 999 结束,这些数都不是 n 的因子,但我们却要将这些数全部枚举一遍。可以发现,如果 n 有一个因子 k,那么它必然有一个因子 n/k,这两个因子中至少有一个是小于等于 \sqrt n 的。
如何证明?我们使用反证法,假设 k > \sqrt n 且 n/k > \sqrt n,那么我们有:
n = k * (n / k) > \sqrt n * \sqrt n = n
产生了矛盾!
因此我们只要在 [1, \lfloor \sqrt n \rfloor] 的范围内枚举 n 的因子 x(这里 \lfloor a \rfloor 表示对 a 进行下取整),这些因子都小于等于 \sqrt n。在这之后,我们倒过来在 [\lfloor \sqrt n \rfloor, 1] 的范围内枚举 n 的因子 x,但我们真正的用到的因子是 n/x。这样一来,我们就从小到大枚举出了 n 的所有因子。
最后需要注意一种特殊情况:如果 n 是完全平方数,那么满足 x^2 = n 的因子 x 被枚举了两次,需要忽略其中的一次。