leetcode每日一题系列-650-只有两个键的键盘-「暴力+dfs」-「记忆化存储+dfs」+「动态规划」

425 阅读3分钟

leetcode-650-只有两个键的键盘

[博客链接]

菜🐔的学习之路

掘金首页

[题目链接]

题目链接

[github地址]

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(n2n^2)
  • 空间复杂度:O(n2n^2)

思路二: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(n2n^2)
  • 空间复杂度:O(n2n^2)

思路三:动态规划

  • 都已经记忆化存储了自然可以想到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(n2n^2)
  • 空间复杂度:O(n2n^2)