题目描述

✅ 1492. n 的第 k 个因子

image-20260929084844562

image-20260929084844659

题意分析

将正整数 n 的所有正因子按升序排列,返回第 k 个。因子必须能整除 n,排名从一开始;因子总数不足 k 时返回 -1。

每个因子只计一次,完全平方数的平方根也不能重复出现。只需要找指定排名,不必保存并排序所有因子。

解法:两趟因子配对枚举

核心思路

[!blue]

如果 factor 是因子,n / factor 也是因子,两个数至少有一个不大于平方根。因此只检查一到平方根就能找到全部因子对。

第一遍将 factor 递增,命中的小因子本身已经是升序。每找到一个就将剩余排名 k 减一,减到零时直接返回。

如果小因子还不够,答案就在对应的大因子中。但小因子越大,对应的 n / factor 越小,所以第二遍必须从平方根扫描边界向一递减,这样输出的大因子才是升序。

非因子在第二遍仍要跳过;若 factor == n / factor,说明两者就是同一个平方根,第一遍已经计过,也要跳过。其他大因子均严格大于第一遍的小因子,所以两遍拼起来正好是完整升序。

循环用 factor <= n / factor 判断是否在平方根以内,避免通过乘法平方比较;limit 保存扫描到的边界,不要求它本身恰好是因子。

解题步骤

  1. 从一开始枚举小于或等于平方根的候选,记录扫描边界。
  2. 能整除时将剩余排名减一,归零就返回当前小因子。
  3. 从记录的边界反向扫到一,跳过非因子和已计过的平方根。
  4. 每找到一个互补大因子,再将排名减一,归零时返回 n / factor。
  5. 两遍都结束仍未归零,则返回 -1。

代码实现

class Solution {
    public int kthFactor(int n, int k) {
        // 记录平方根扫描边界,不是已找到的因子数量。
        int limit = 0;

        for (int factor = 1; factor <= n / factor; factor++) {
            limit = factor;

            if (n % factor == 0 && --k == 0) {
                return factor;
            }
        }

        // 反向扫描小因子,才能按升序得到互补的大因子。
        for (int factor = limit; factor >= 1; factor--) {
            // 跳过非因子和已经计数的平方根。
            if (n % factor != 0 || factor == n / factor) {
                continue;
            }

            if (--k == 0) {
                return n / factor;
            }
        }

        return -1;
    }
}
func kthFactor(n int, k int) int {
    // 记录平方根扫描边界,不是已找到的因子数量。
    limit := 0
    for factor := 1; factor <= n/factor; factor++ {
        limit = factor
        if n%factor == 0 {
            k--
            if k == 0 {
                return factor
            }
        }
    }

    // 反向扫描小因子,才能按升序得到互补的大因子。
    for factor := limit; factor >= 1; factor-- {
        // 跳过非因子和已经计数的平方根。
        if n%factor != 0 || factor == n/factor {
            continue
        }
        k--
        if k == 0 {
            return n / factor
        }
    }
    return -1
}

复杂度分析

  • 时间复杂度:$O(\sqrt n)$,最多在平方根范围内扫描两遍。
  • 空间复杂度:$O(1)$,只保存扫描边界及剩余排名。

关键点总结

[!green]

  • 因子配对把枚举范围缩到平方根以内。
  • 小因子升序对应大因子降序,反向扫描才能接成完整升序。
  • 剩余排名跨两遍连续递减,平方根只计一次。

易错点总结

[!yellow]

  • 找到小因子就立即计入互补大因子,会打乱整体大小顺序。
  • 完全平方数重复计数平方根,会使后续排名错位。
  • 第二遍只检查保存的边界而不重新检查整除,会把非因子也计入。
  • 只枚举小因子后直接返回不存在,会漏掉大于平方根的有效答案。

相似题目

题目 难度 关联与区别
1390. 四因数 中等 同样按平方根成对枚举因子,本题还需按小因子升序、大因子降序确定第k项。
507. 完美数 简单 因子枚举相同,原题求真因子和,本题按大小选择一个因子。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2024/85886952
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!