leetcode-650-只有两个键的键盘
[博客链接]
[题目链接]
[github地址]
[题目描述]
最初记事本上只有一个字符 '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
思路一:暴力dfs
- 我们可以记录当前剪贴板上的字符以及目前的字符
- 每增加一次操作res++
- 操作分两种情况
- 复制剪贴板上的字符串
- 将当前字符串更新到剪贴板上
- 这两种操作没种操作都是res++
- 并且不会出现连续两次更新剪贴板的操作(这样效果一样所以会影响最小次数)
- 因为最多操作就是n次,所以可以定义最大值1010
class Solution {
int target = 0, INF = 1010;
public int minSteps(int n) {
target = n;
return dfs(1,0);
}
public int dfs(int cur, int paste){
if(cur > target){
return INF;
}
if(cur == target){
return 0;
}
int res = INF;
if(paste > 0){
res= Math.min(res, dfs(cur + paste, paste));
}
if(cur != paste){
res= Math.min(res,dfs(cur,cur));
}
return res+1;
}
}
- 时间复杂度:O()
- 空间复杂度:O()
思路二:dfs+记忆化
- 上述题解可以清楚的发现有两个可变元素,所以可以使用记忆化来进行优化
- 定义数组memo[][]
- m[i][j]记录当前i个字符剪贴板上j哥字符的最小操作次数
class Solution {
int target = 0, INF = 1010;
int[][] memo ;
public int minSteps(int n) {
target = n;
memo =new int[n][n];
return dfs(1,0);
}
public int dfs(int cur, int paste){
if(cur > target){
return INF;
}
if(cur == target){
return 0;
}
if(memo[cur][paste]!=0){
return memo[cur][paste];
}
int res = INF;
if(paste>0){
res = Math.min(res, dfs(cur+paste,paste));
}
if(cur != paste){
res = Math.min(res, dfs(cur,cur));
}
memo[cur][paste] = Math.min(res+1,memo[cur][paste]);
return res+1;
}
}
- 时间复杂度:O()
- 空间复杂度:O()
思路三:动态规划
- 都已经记忆化存储了自然可以想到dp的解决方案了
- 定义dp数组dp[i][j]
- 表示当前i个字符,剪贴板上j个字符的最小方案数量
- 初始化状态
- dp[1][0] = 0; dp[1][1] = 1;
- 其余dp[i][j] = INF;
- 转移过程
- dp[i][j] = dp[i-j][j] + 1
- 同时需要记录一个最小值min,记录到达当前状态的最小值,方便更新复制当前字符数量的最小操作数量
- min = Math.min(min,dp[i][j]);
- 当前dpi[i][i]表示复制操作的最小值为dp[i][i] = min + 1
public int minSteps(int n) {
int INF = 1010;
int[][] dp =new int[n+1][n+1];
for(int[] num:dp){
Arrays.fill(num,INF);
}
dp[1][0] = 0;
dp[1][1] = 1;
for(int i = 2; i <=n;i++){
int min = INF;
for(int j = 0; j <= i/2; j++){
dp[i][j] = dp[i-j][j]+1;
min= Math.min(min, dp[i][j]);
}
dp[i][i] = min + 1;
}
int res = INF;
for(int num:dp[n]){
res = Math.min(res, num);
}
return res;
}
- 时间复杂度:O()
- 空间复杂度:O()