650. 只有两个键的键盘
最初在一个记事本上只有一个字符 ‘A’。你每次可以对这个记事本进行两种操作:
1.
Copy All (复制全部) : 你可以复制这个记事本中的所有字符(部分的复制是不允许的)。
2.
Paste (粘贴) : 你可以粘贴你上一次复制的字符。
给定一个数字 n 。你需要使用最少的操作次数,在记事本中打印出恰好 n 个 ‘A’。输出能够打印出 n 个 ‘A’ 的最少操作次数。
示例 1:
输入: 3
输出: 3
解释:
最初, 我们只有一个字符 ‘A’。
第 1 步, 我们使用 Copy All 操作。
第 2 步, 我们使用 Paste 操作来获得 ‘AA’。
第 3 步, 我们使用 Paste 操作来获得 ‘AAA’。
个人思路1.0:
设dp[n]为,组成n个字符所需要的最少操作数
经观察得
至此,可发现该题与数的最大公因数有关,n的最大公因数决定了剪切板上我们的字符串中,允许的最大长度。
设mcf为n的最大公因数:dp[n]=dp[mcf]+1C+(n/mcf-1)P (n>=2) (1)
在运用公式(1)时发现,每次运算并不用把dp数组从小到大都填满,例如dp[9]只需要dp[3]和dp[1]的值;
推测dp[64]只需要dp[32],dp[16],dp[8],dp[4],dp[2],dp[1];
只需要套娃不断寻找最大公因数,直到1为止4,并记录沿途值。
那就不用dp数组了,用递归自顶向下求解即可
代码1.0
class Solution {
public:
vector<int> MCFArr;
void getMCF(const int& num)
{
int maxMCF = 0;
for (int i = 1; i <= num / 2; ++i)
{
if (num % i == 0) maxMCF = i;
}
if (maxMCF != 1)
{
getMCF(maxMCF);
}
MCFArr.push_back(maxMCF);
}
int minSteps(int n) {
if(n==1)
{
return 0;
}
getMCF(n);
MCFArr.push_back(n);
int len = MCFArr.size();
vector<int> dp(len);
dp[0] = 0;
for (int i = 1; i < len; ++i)
{
dp[i] = dp[i - 1] + 1 + (MCFArr[i] / MCFArr[i - 1] - 1);
}
return dp[len - 1];
}
};
通过递归(套娃)将n的最大公因数的最大公因数的…最大公因数,自小到大放到数组MCFArr中,最后加入n自己。创建与MCFArr等长的dp数组,用于存储下标对应的最大公因数的最少操作次数,再通过公式 dp[n]=dp[n-1]+1Copy+(MCFArr[n]/MCFArr[n-1]-1)Paste求解!