Skip to content

两个键的键盘

约 682 字大约 2 分钟

贪心

2025-02-23

650. 两个键的键盘

最初记事本上只有一个字符 'A' 。你每次可以对这个记事本进行两种操作:

  • Copy All(复制全部):复制这个记事本中的所有字符(不允许仅复制部分字符)。
  • Paste(粘贴):粘贴 上一次 复制的字 符。

给你一个数字 n ,你需要使用最少的操作次数,在记事本上输出 恰好 n'A' 。返回能够打印出 n'A' 的最少操作次数。

示例 1:

输入:3
输出:3
解释:
最初, 只有一个字符 'A'。
第 1 步, 使用 Copy All 操作。
第 2 步, 使用 Paste 操作来获得 'AA'。
第 3 步, 使用 Paste 操作来获得 'AAA'。

示例 2:

输入:n = 1
输出:0

提示:

  • 1 <= n <= 1000

数学+贪心

定义 x 次操作为 1 次 Copy All + x-1 次 Paste,它会将原来的字符串变为原来的 x 倍。 注意 x 必须大于 1。

最小操作次数方案等价于以下操作流程:

  1. 起始对长度为 1 的记事本字符进行 1 次 Copy All + k1−1 次 Paste 操作(消耗次数为 k1,得到长度为 k1 的记事本长度);
  2. 对长度为为 k1 的记事本字符进行 1 次 Copy All + k2−1 次 Paste 操作 (消耗次数为 k1+k2,得到长度为 k1∗k2 的记事本长度)
  3. ...

最终经过 k 次“动作”之后,得到长度为 n 的记事本长度,即有:

n=k1∗k2∗...∗kx

问题转化为:如何对 n 进行因式分解,使得因子之和最小。

注意例子: 8=2*4,2+4=6<8,由此可知非平凡因式分解后因子之和会变小,所以我们必须尽可能地分解 n。

class Solution {
    public int minSteps(int n) {
        int ans = 0; // 初始化操作次数为 0
        
        // 从 2 开始枚举可能的因子,直到 i * i > n,这是因为
        // 1 是平凡因子,所以不用不考虑。当 i*i>n 时,i 不可能整除 n。
        for (int i = 2; i * i <= n; i++) {
            // 如果 i 是 n 的因子
            while (n % i == 0) {
                ans += i; // 将因子 i 累加到操作次数中
                n /= i;   // 用因子 i 将 n 除尽,因为我们要尽可能地分解 n
            }
        }
        
        // 如果此时 n 不是 1,说明 n 本身是一个大素数。重点。
        // 如果 n 不是素数,则上面的 for 循环一定能把 n 除到 1。
        if (n != 1) ans += n; // 将剩余的素数因子累加到操作次数中
        
        return ans; // 返回最小操作次数
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)