只有两个键的键盘 图解题解
这道题到底在问什么
- 输入
- n = 3
- 输出
- 3 (复制 1 次,粘贴 2 次)
- 输入
- n = 1
- 输出
- 0 (初始已经是 1 个,不用操作)
- 输入
- n = 9
- 输出
- 6 (拆成 3 乘 3,每段 3 步)
最优解:为什么这么做
一句话答案:LeetCode 650 只有两个键的键盘:只能复制全部和粘贴,凑够 n 个 A 求最少操作。把长度扩大 d 倍需 d 步,最优拆法是质因数分解,答案即 n 的质因子之和,试除法时间 O(√n)、空间 O(1)。
复制粘贴凑出 n 个 A,最少按几次
给一个正整数 n,屏幕初始只有 1 个 A。每次操作二选一:复制全部内容到剪贴板,或把剪贴板内容粘贴一次接到末尾。求最少多少次操作让屏幕恰好是 n 个 A。题面给三组:n=3 要 3 次,n=1 要 0 次,n=9 要 6 次。
为什么把每次复制粘贴都试一遍会爆
顺题意最容易想到把操作序列一步步试:每步要么复制、要么粘贴,铺开成一棵树往下搜哪条路最先凑够 n 个 A。可复制时机选择很多、序列长度没有上界,搜索树指数级膨胀,n 稍大就搜不完。浪费在于同一个中间长度被不同路径反复凑到,没记下来复用。
把长度扩大 d 倍,为什么正好花 d 步
别盯着一次次按键,看一整段操作。屏幕长度要变大,唯一办法是先复制一次、再连续粘贴若干次。当前有 k 个 A,复制 1 次后每粘贴一次多 k 个,粘贴 d-1 次总共变成 k 乘 d,即扩大到 d 倍。这一段花复制 1 次加粘贴 d-1 次,正好 d 次。
所以凑出 n 个 A,本质是把 n 写成若干个大于 1 的整数连乘,每个乘数 d 花掉 d 步,总步数就是这些乘数相加,求最少操作即找乘数之和最小的拆法。
dp 为什么沿因子转移,答案为什么是质因子和
把想法写成递推。设 dp[x] 是从 1 个 A 凑到 x 个 A 的最少操作。凑到 x 的最后一段是把某个因子 m 扩大到 x(m 能整除 x),倍数 x/m、花 x/m 步,接在 dp[m] 后。枚举 x 的所有因子取最小,dp[x]=min(dp[m]+x/m)。
把 n 拆成 a 乘 b 两段共花 a+b 步;只要 a、b 都不小于 2,就有 a+b 不超过 a 乘 b(比如 2+3=5 ≤ 2×3=6)。所以因子只要还是合数、还能再拆,拆开总步数只会不增。一路拆到剩下全是质数,各段之和最小,答案就是 n 的全部质因子相加。代码不必开 dp 数组,从最小质数试除 n,除得尽就累加进答案,时间 O(√n)。
拿 n=9 把因子拆法亲手走一遍
dp[1]=0,先看 dp[3]:因子只有 1,把 1 扩到 3 倍花 3 步,dp[3]=3。到 dp[9],因子有 1 和 3:走 1 是扩到 9 倍花 9 步得 9;走 3 是把 3 扩到 3 倍花 3 步、接在 dp[3]=3 后得 3+3=6,取小的 6,dp[9]=6,和题面对上。
换质因数分解看更快:9=3 乘 3,两个质因子相加 3+3=6。再看 n=3 本身是质数、只有 3 一个质因子,答案 3;n=1 没有质因子,答案 0——都和题面一致。
试除到 √n 就够,n=1 和质数两处别写错
试除只需从 2 到 √n:大于 √n 的因子至多剩一个,循环后若剩下的数还大于 1,把它当最后一个质因子补加,时间 O(√n)、空间 O(1)。
n=1 是头号陷阱——没有质因子,答案就是 0,别顺手返回 1。质数(7、13 这种)也容易漏,√n 以内没有因子整除它,循环一次都不加,全靠结尾那句『剩下的数大于 1 就补进来』兜住。还有个手滑:收因子时加的是因子 d 本身、不是次数 1,写成加 1 会把答案压小。
▶ 动画逐步走查(共 14 步)——想跟着动画一帧帧对照就展开
- 3记住这条:答案 = n 的所有质因子相加。下面用 n=60 一步步试除,把 60 拆成 2 x 2 x 3 x 5。
- 6开局:要分解 60。从最小质数 d=2 开始试除,能整除就把 d 收进答案。
- 7轮到 d=2(紫色)。先看 2×2=4 是否 ≤ 剩余 n=60,成立才继续试除;若 d×d 已大于剩余 n,说明没有更小因子可拆,循环退出,再把剩余 n(若 > 1)作为最后一个质因子补加。
- 860 能被 2 整除。说明这一段要把长度扩大 2 倍,花 2 步。把 2 收进答案。
- 9收下质因子 2(绿色):ans 加 2 变成 2,剩余 n 缩成 30。继续看 30 还能不能再被 2 整除。
- 1030 能被 2 整除。说明这一段要把长度扩大 2 倍,花 2 步。把 2 收进答案。
- 11收下质因子 2(绿色):ans 加 2 变成 4,剩余 n 缩成 15。继续看 15 还能不能再被 2 整除。
- 1215 不再被 2 整除,d=2 这一段拆完了。d 加 1,看下一个候选。
- 13轮到 d=3(紫色)。先看 3×3=9 是否 ≤ 剩余 n=15,成立才继续试除;若 d×d 已大于剩余 n,说明没有更小因子可拆,循环退出,再把剩余 n(若 > 1)作为最后一个质因子补加。
- 1415 能被 3 整除。说明这一段要把长度扩大 3 倍,花 3 步。把 3 收进答案。
- 15收下质因子 3(绿色):ans 加 3 变成 7,剩余 n 缩成 5。继续看 5 还能不能再被 3 整除。
- 165 不再被 3 整除,d=3 这一段拆完了。d 加 1,看下一个候选。
- 17试除循环结束后还剩 n=5,且 5 > 1,说明它是一个大质因子(再没有更小因子能拆它),直接收进答案。
- 18加上最后这个质因子 5,ans = 12,剩余 n 归 1。60 = 2 × 2 × 3 × 5,质因子之和 = 12,就是最少操作次数。
⚠️ 容易写错的地方
✗ 错:收因子时 ans 加的是「次数」如 +1
✓ 对:ans 加的是因子本身 d
扩大到 d 倍要复制 1 次加粘贴 d-1 次,共 d 次,所以加 d
✗ 错:试除到 n 才停,O(n)
✓ 对:d×d ≤ n 即停,O(√n)
大于 √n 的因子最多剩一个,循环后单独加即可
✗ 错:忘了循环结束后剩余 n > 1 要补加
✓ 对:末尾 ans += (n > 1 ? n : 0)
n 本身是质数(如 7、13)时循环里根本没除到它
✗ 错:n = 1 时返回 1
✓ 对:n = 1 返回 0
初始已有 1 个 A,无需任何操作
完整代码(Python / C++ / Java)
Python
class Solution:
def minSteps(self, n: int) -> int:
ans = 0
d = 2
while d * d <= n:
while n % d == 0:
ans += d
n //= d
d += 1
return ans + (n if n > 1 else 0)C++
class Solution {
public:
int minSteps(int n) {
int ans = 0;
for (int d = 2; d * d <= n; ++d) {
while (n % d == 0) { ans += d; n /= d; }
}
return ans + (n > 1 ? n : 0);
}
};Java
import java.util.*;
class Solution {
public int minSteps(int n) {
int ans = 0;
for (int d = 2; d * d <= n; d++) {
while (n % d == 0) { ans += d; n /= d; }
}
return ans + (n > 1 ? n : 0);
}
}复杂度
时间
O(√n)
d 只需试到 √n,最多 √n 次
空间
O(1)
只用 ans、d、n 几个变量
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 只有两个键的键盘 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么拆成质因子一定最省,不能有更优的拆法?+
关键在一个不等式:把长度扩大 a 乘 b 倍,分两段做要 a+b 步,而对任意都不小于 2 的整数 a、b,都有 a+b 不超过 a 乘 b。所以只要某个因子还是合数、还能写成两个不小于 2 的数相乘,就把它拆开,总步数只会不增。一直拆到每段都是质数就再也拆不动,这时各段之和最小,正是把 n 分解成质因子后相加。
用动态规划怎么写,复杂度和试除法比如何?+
设 dp[x] 是凑出 x 个 A 的最少操作,枚举 x 的每个因子 m,dp[x]=min(dp[m]+x/m),从小到大填到 dp[n]。找因子那步对每个 x 都要扫一遍,整体是 O(n√n) 到 O(n²),比质因数分解的 O(√n) 慢,但更直观、也更好推广到别的凑数题,面试里两种都值得会。这种凑数型 DP,可对照整数拆分 LeetCode 343 一起看。
n=1 为什么答案是 0,而不是 1?+
初始屏幕上就已经有 1 个 A,题目要的正好是 1 个,什么操作都不用做,所以是 0 步。数学上 1 没有质因子,质因子之和是 0,也对得上。写代码时容易顺手把它当成还要操作一次而返回 1,是这题最典型的边界错。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 只有两个键的键盘 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。