leetcode打卡-动态规划

97. 交错字符串

leetcode题目链接:https://leetcode.cn/problems/interleaving-string/

leetcode AC记录:

思路:话不多说,动态规划。使用dp[i][j]表示s1从下标0开始,长度为i的子串,和s2从下标0开始,长度为j的子串,能否构成下标从0开始,长度为i+j的子串。状态转移方程为dp[i][j] = (dp[i-1][j] && s1.charAt(i-1) == s3.charAt(i+j-1)) || (dp[i][j-1] && s2.charAt(j-1) == s3.charAt(i+j-1))。

代码如下:

public boolean isInterleave(String s1, String s2, String s3) {
        boolean[][] dp = new boolean[s1.length()+1][s2.length()+1];

        if(s2.length() + s1.length() != s3.length()) {
            return false;
        }

        //dp[i][j]表示s1从下标0开始,长度为i的子串,和s2从下标0开始,长度为j的子串,能否构成下标从0开始,长度为i+j的子串
        //状态转移方程为dp[i][j] = (dp[i-1][j] && s1.charAt(i-1) == s3.charAt(i+j-1)) || (dp[i][j-1] && s2.charAt(j-1) == s3.charAt(i+j-1))
        
        dp[0][0] = true;

        for(int i = 0;i <= s1.length();i++) {
            for(int j = 0;j <= s2.length();j++) {
                if(i > 0 && j > 0) {
                    dp[i][j] = (dp[i-1][j] && s1.charAt(i-1) == s3.charAt(i+j-1)) || (dp[i][j-1] && s2.charAt(j-1) == s3.charAt(i+j-1));
                } else if(i > 0) {
                    dp[i][j] = dp[i-1][j] && s1.charAt(i-1) == s3.charAt(i+j-1);
                } else if(j > 0) {
                    dp[i][j] = dp[i][j-1] && s2.charAt(j-1) == s3.charAt(i+j-1);
                }
            }
        }

        return dp[s1.length()][s2.length()];
    }

 221. 最大正方形

leetcode题目链接:https://leetcode.cn/problems/maximal-square/

leetcode AC记录:

思路:最大正方形,使用dp[i][j]表示以i,j为正方形右下角顶点的最大边长。状态转移方程为dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1])。初始化边缘,即i=0,j=[0-length]和i=[0-length][0]为如果[i][j]为1,则面积为1,否则为0。中间使用结果记录最大边长,最后结果是边长的乘积。

代码如下:

public int maximalSquare(char[][] matrix) {
        //使用dp[i][j]表示以i,j为正方形右下角的最大正方形面积
        //dp[i][j] = min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1
        int[][] dp = new int[matrix.length][matrix[0].length];
        int res = 0;
        
        //初始化dp数组
        for(int i = 0;i < matrix.length;i++) {
            if(matrix[i][0] == '1') {
                dp[i][0] = 1;
                res = 1;
            }
        }

        for(int i = 0;i < matrix[0].length;i++) {
            if(matrix[0][i] == '1') {
                dp[0][i] = 1;
                res = 1;
            }
        }

        for(int i = 1;i < matrix.length;i++) {
            for(int j = 1; j < matrix[0].length;j++) {
                if(matrix[i][j] == '1') {
dp[i][j] = Math.min(dp[i-1][j-1], Math.min(dp[i][j-1], dp[i-1][j])) + 1;
                }
                
                if(res < dp[i][j]) {
                    res = dp[i][j];
                }
            }
        }
        
        
        return res * res;
    }

509. 斐波那契数

leetcode题目链接:https://leetcode.cn/problems/fibonacci-number/


leetcode AC记录:

代码如下:

 public int fib(int n) {
        if(n <= 1) {
            return n;
        }

        int a = 0;
        int b = 1;
        int c = 0;
        for(int i = 2;i <= n;i++) {
            c = a + b;
            a = b;
            b = c;
        }

        return c;
    }

70. 爬楼梯

leetcode题目链接:https://leetcode.cn/problems/climbing-stairs

leetcode AC记录:

代码如下:

public int climbStairs(int n) {
        if(n <= 1) {
            return n;
        }

        int a = 1;
        int b = 1;
        int c = 0;
        for(int i = 2;i <= n;i++) {
            c = a+b;
            a = b;
            b = c;
        }
        return c;
    }

746. 使用最小花费爬楼梯

leetcode题目链接:https://leetcode.cn/problems/min-cost-climbing-stairs

leetcode AC记录:

思路:使用dp[i]表示到下标为i所付出的成本,状态转移方程:dp[i] = min(dp[i-1],dp[i-2]) + cost[i]。

代码如下:

public int minCostClimbingStairs(int[] cost) {
        int[] dp = new int[cost.length];
        //使用dp[i]表示到下标为i所付出的成本
        //状态转移方程:dp[i] = min(dp[i-1],dp[i-2]) + cost[i]
        dp[0] = cost[0];
        dp[1] = cost[1];

        for(int i = 2;i < cost.length;i++) {
            dp[i] = Math.min(dp[i-1], dp[i-2]) + cost[i];
        }

        return Math.min(dp[cost.length-1], dp[cost.length-2]);
    }

1137. 第 N 个泰波那契数

leetcode题目链接:https://leetcode.cn/problems/n-th-tribonacci-number/

leetcode AC记录:

代码如下:

public int tribonacci(int n) {
        
        if(n == 0) {
            return 0;
        } else if(n <= 2) {
            return 1;
        }

        int a = 0;
        int b = 1;
        int c = 1;
        int d = 0;
        for(int i = 3;i <= n;i++) {
            d = a + b + c;
            a = b;
            b = c;
            c = d;
        }
        return d;
    }

 873. 最长的斐波那契子序列的长度

leetcode题目链接:https://leetcode.cn/problems/length-of-longest-fibonacci-subsequence

leetcode AC记录:

思路:使用dp[j][i]表示以j和i下标所在位置为末尾的斐波纳切数列的最大长度。状态转移方程为:dp[j][i] =

Math.max(dp[index][j] + 1, 3),index < j && index >= 0

0, index = -1

其中使用map记录arr[i]和i的关系,index = map.getOrDefault(arr[i]-arr[j], -1)

代码如下:

public int lenLongestFibSubseq(int[] arr) {
        //使用dp[i][j]表示数组arr以下标i作为结尾的斐波那契数列最大长度,j为最长菲波纳切数列的倒数第二个元素下标
        Map<Integer, Integer> map = new HashMap<>(arr.length);
        for(int i = 0; i < arr.length;i++) {
            map.put(arr[i], i);
        }

        int[][] dp = new int[arr.length][arr.length];
        int res = 0;
        for(int i = 2;i < arr.length;i++) {
            for(int j = i-1; j >= 0;j--) {
                int diff = arr[i] - arr[j];
                int index = map.getOrDefault(diff, -1);
                if(index >= 0 && index < j) {
                    dp[j][i] = Math.max(dp[index][j] + 1, 3);
                }

                if(res < dp[j][i]) {
                    res = dp[j][i];
                }
            }
        }

        return res;
    }

62. 不同路径

leetcode题目链接:https://leetcode.cn/problems/unique-paths

leetcode AC记录:

代码如下:

public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        for(int i = 0;i < m;i++) {
            dp[i][0] = 1;
        }

        for(int i = 0;i < n;i++) {
            dp[0][i] = 1;
        }

        for(int i = 1;i < m;i++) {
            for(int j = 1;j < n;j++) {
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }

        return dp[m-1][n-1];

    }

63.不同路径II

leetcode题目链接:https://leetcode.cn/problems/unique-paths-ii/

leetcode AC记录:

思路:如果obstacleGrid[0][0]等于1的话,直接返回0。使用动态规划,dp[i][j]保存的是从 0,0 到当前位置的路径总和,初始化操作:

初始化dp数组第一列和第一行,如果当前数字为1,dp数组的值为0;如果当前数字为0的话,dp数组的值为1;

遍历obstacleGrid数组,如果当前位置的值是1的话,路径和为0;如果当前位置的值是0的话,路径和的状态转移方程为dp[i][j]=dp[i-1][j-1]。

代码如下:

public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int[][] dp = new int[obstacleGrid.length][obstacleGrid[0].length];

        if(obstacleGrid[0][0] == 1) {
            return 0;
        }

        dp[0][0] = 1;

        for(int i = 1;i < obstacleGrid.length;i++) {
            if(obstacleGrid[i][0] == 0) {
                dp[i][0] = dp[i-1][0] == 0 ? 0 : 1;
            }
        }

         for(int i = 1;i < obstacleGrid[0].length;i++) {
            if(obstacleGrid[0][i] == 0) {
                dp[0][i] = dp[0][i-1] == 0 ? 0 : 1;
            }
        }

        for(int i = 1;i < obstacleGrid.length;i++) {
            for(int j = 1;j < obstacleGrid[0].length;j++) {
                if(obstacleGrid[i][j] == 0) {
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }
            }
        }

        return dp[obstacleGrid.length-1][obstacleGrid[0].length-1];
        
    }

343. 整数拆分

leetcode题目链接:https://leetcode.cn/problems/integer-break

leetcode AC记录:

思路:动态规划,使用dp[i]存储整数和为i的最大乘积。状态转移方程为dp[i] = max(dp[j] * (i-j), dp[i], (i-j)* j)。

代码如下:

public int integerBreak(int n) {
        //dp【i】数组表示以i为和的最大乘积
        int[] dp = new int[n+1];
        dp[0] = 0;
        dp[1] = 1;
        dp[2] = 1;

        for(int i = 3;i <= n;i++) {
            for(int j = i-1;j >= 1;j--) {
                dp[i] = Math.max(Math.max(dp[j] * (i-j), dp[i]), j * (i-j));
            }
        }

        return dp[n];
    }

96. 不同的二叉搜索树

leetcode题目链接:https://leetcode.cn/problems/unique-binary-search-trees

leetcode AC记录:

思路:使用动态规划。dp[i]表示以节点1到i组成的二叉搜索树的总量,状态转移方程为dp[i] = sum(dp[k] * dp[i-k-1])。因为都是顺序递增的,所以说只用关心节点的数量就行,不用关心节点具体的值。举个例子,比如以1到3组成的二叉搜索树的总量计算过程为:分别以1,2,3为头节点,

以1为头节点时,将数组分为左右子树【左子树:null】【头节点1】【右子树:2,3】,结果为dp[0] * dp[2];

以2为头节点时,将数组分为左右子树【左子树:1】【头节点2】【右子树:3】,结果为dp[1] * dp[1];

以3为头节点时,将数组分为左右子树【左子树:1,2】【头节点3】【右子树:null】,结果为dp[2] * dp[0];

所以dp[3] = dp[0] * dp[2] + dp[1] * dp[1]  + dp[2] * dp[0],符合我们的状态转移方程。

其中,初始化操作为:dp[0] = 1, dp[1] = 1, dp[2] = 2。

代码如下:

 public int numTrees(int n) {
        //使用dp【i】表示以节点1到i的二叉搜索树的总量
        //状态转移方程为dp[i] = sum(dp[k] * dp[i-k-1])
        int[] dp = new int[n+1];
        if(n <= 2) {
            return n == 2 ? 2 : 1;
        }
        
        dp[0] =1;
        dp[1] = 1;
        dp[2] = 2;
        for(int i = 3;i <= n;i++) {
            for(int k = 0;k < i;k++) {
                dp[i] += dp[k] * dp[i-k-1];
            }
        }

        return dp[n];
    }

279.完全平方数

leetcode题目链接:https://leetcode.cn/problems/perfect-squares/

leetcode AC记录:

思路:动态规划,使用dp[i]表示组成和为i的完全平方数的最小个数。状态转移方程为dp[i] = dp[i-j*j] +1。

代码如下:

public int numSquares(int n) {
        //使用动态规划
        //状态转移方程为dp[i] = dp[j] + dp[i-(j*j)]
        int[] dp = new int[n+1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0;
        dp[1] = 1;
        for(int i = 2;i <= n;i++) {
            for(int j = 1;j * j <= n;j++) {
                if(i - j*j >= 0) {
                    dp[i] = Math.min(dp[i-j*j]+1, dp[i]);
                }
            }
        }
        return dp[n];
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值