力扣650. 只有两个键的键盘 递归法素数分解法与动态规划法多种解法!
Posted weixin_43739821
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了力扣650. 只有两个键的键盘 递归法素数分解法与动态规划法多种解法!相关的知识,希望对你有一定的参考价值。
最初在一个记事本上只有一个字符 ‘A’。你每次可以对这个记事本进行两种操作:
Copy All (复制全部) : 你可以复制这个记事本中的所有字符(部分的复制是不允许的)。
Paste (粘贴) : 你可以粘贴你上一次复制的字符。
给定一个数字 n 。你需要使用最少的操作次数,在记事本中打印出恰好 n 个 ‘A’。输出能够打印出 n 个 ‘A’ 的最少操作次数。
示例 1:
输入: 3
输出: 3
解释:
最初, 我们只有一个字符 ‘A’。
第 1 步, 我们使用 Copy All 操作。
第 2 步, 我们使用 Paste 操作来获得 ‘AA’。
第 3 步, 我们使用 Paste 操作来获得 ‘AAA’。
说明:
n 的取值范围是 [1, 1000] 。
解法一递归思路(数学法):
首先显然,如果n是素数,我们只能通过复制一次加粘贴n-1次得到,因为题目已知只能复制已有的全部字符。
如果其是合数,我们先找到其最大因子i:n=i*(n/i),则我们需要先得到i个字符,再复制一次,粘贴(n/i)-1次即可得到n个字符,为什么要这样做呢?比如18=2×9,是复制一次粘贴17次少还是复制一次粘贴一次得到AA,再复制一次再粘贴8次一共11次少? 显然11次少,所以最优最少的求法就是将n尽可能的分解到不能再分解的地步。
所以有:
minSteps(n)=minSteps(i)+n/i
得到递归公式,代码显然得出:
int minSteps(int n) {
if (n == 1) {//默认原有一个字符,不需要任何操作
return 0;
}
for (int i = n / 2; i > 1; i--) {//从n/2开始寻找n的最大因子
if (n % i == 0) {
return minSteps(i) + n / i;
}
}
return n;//如果n为素数则需要n次操作
}
解法二素数分解法:
借由解法一的递归思路,我们带入实例:
比如n=48 则n=24×2
而24=12×2 12=6×2 6=3×2
所以minSteps(48) =2+2+2+2+minSteps(3)
又因为3是素数 所以minSteps(3)=3
所以我们可知,此题的求解就是将给定数字分解为素因子,并求和。代码显然:
int minSteps(int n) {
int all = 0;
for (int i = 2; i <= n; i++) {//从2开始不断寻找n的素因子
while (n % i == 0) {//如果i是n的素因子,则需要一次性将n中该素因子除尽
all += i;
n /= i;
}
}
return all;
}
解法三动态规划:
设置dp[i]的含义:得到i需要的最少次数
则dp[1]=0,dp[0]不用,题目所求即为求dp[n]
n为素数,则dp[n]=n
n为合数,若n可以被i整除,则说明可以通过复制粘贴i得到n个A,复制粘贴次数为1+(n/i-1)=n/i
所以我们不断的搜查每个数y的因子并求得对应因子所得出的次数,求出其对应的最终dp[y]循环得到dp[n]。
则得到递推公式:
dp[n]=min(dp[n],dp[i]+n/i)。
递推公式写出,则代码立即有:
int minSteps(int n) {
vector<int> dp(n + 1);
dp[1] = 0;
for (int i = 2; i <= n; i++) {
dp[i] = i;//i为i的最大次数,当i为素数时dp[i]=i
for (int j = 2; j < i/2; j++)//优化算法:从2往上查找因数只需要查到其平方根大小即可
{
if (i % j == 0)
dp[i] = min(dp[j] + i/j,dp[i]);
}//不断循环求出其最佳值
}
return dp[n];
}
以上是关于力扣650. 只有两个键的键盘 递归法素数分解法与动态规划法多种解法!的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 650 只有两个键的键盘[递归 动态规划] HRRODING的LeetCode之路
[M数学] lc650. 只有两个键的键盘(dp+思维+质因数)
[M数学] lc650. 只有两个键的键盘(dp+思维+质因数)