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
class solution{
public int minSteps(int n) {
int dp[] = new int[n + 1];
dp[0] = dp[1] = 0;
for (int i = 2; i <= n; i++) {
//输入的如果是素数,值为本身
dp[i] = i;
}
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= i; j++) {
if (i % j == 0) {
//可以这样考虑,dp[j]的值为最小的dp[i/j]的次数加上复制i/j的一次,再加上粘贴的i/j-1次
if ((dp[j] + (i / j)) < dp[i]) {
dp[i] = dp[j] + (i / j);
}
}
}
}
return dp[n];
}
}
这一题的思路是动态规划,主要是找到状态转移方程,我们注意到只能粘贴最后一次复制的东西,这就是重点。
d
p
[
i
]
=
m
i
n
(
d
p
[
i
/
j
]
+
i
/
j
,
d
p
[
i
]
)
dp[i]=min(dp[i/j]+i/j,dp[i])
dp[i]=min(dp[i/j]+i/j,dp[i])
其中
i
/
j
\color{red}{i/j}
i/j是这样得到的,首先我们可以通过之前的dp,得到dp[i/j],dp[i/j]的含义是得到i/j个A需要最少的操作次数,如何通过i/j得到i?只需要先复制j个A,这里我们操作了一次,接下来就是一直粘贴,粘贴的次数为i/j-1,因为(i/j-1)*j=i-j,把1和i/j-1相加,得到i/j。