Amber-Leedcode-Java - 代码随想录打卡第38 - 44天-动态规划汇总

本质上感觉是一个相加的问题,状态的转换,由前一种状态推至下一种状态

509. 斐波那契数

较为简单

746. 使用最小花费爬楼梯

62. 不同路径

一开始写的时候被吓到了,但是发现听完一半之后再写还是比较容易的

对于我而言主要是找到逻辑,

class Solution {
    public int uniquePaths(int m, int n) {
        if (m <= 1 || n <=1){
            return 1;
        }
        int[][] result = new int[m][n];
        result[0][0] = 0;
        result[1][0] = 1;
        result[0][1] = 1;
        for (int i = 0;i < m;i++){
            for (int j = 0;j < n; j++){
                if (i > 0 && j > 0){
                    result[i][j] = result[i][j-1] + result[i-1][j];
                }else if (i == 0 && j > 0 && j!=1){
                    result[i][j] = result[i][j-1];
                }else if (j == 0 && i > 0 && i!=1){
                    result[i][j] = result[i-1][j];
                }
        }
    }
      return result[m-1][n-1];
}
}

63. 不同路径 II

秒杀,和前者逻辑差不多,要注意初始化就好


class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        if (m <= 1 || n <=1){
            for (int i = 0;i < m; i++){
                for (int j = 0;j <n; j++){
                    if (obstacleGrid[i][j] == 1){
                        return 0;
                    }
                }
            }
            return 1;
        }
        int[][] result = new int[m][n];
        if (obstacleGrid[0][0] == 1){
            return 0;
        }else{
              result[0][0] = 0;
        }

        if (obstacleGrid[1][0] == 1){
            result[1][0] = 0;
        }else{
            result[1][0] = 1;
        }
        
        if (obstacleGrid[0][1] == 1){
            result[0][1] = 0;
        }else{
            result[0][1] = 1;
        }
        
        for (int i = 0;i < m;i++){
            for (int j = 0;j < n; j++){
                if (obstacleGrid[i][j] == 1){
                    result[i][j] = 0;
                }else if (i > 0 && j > 0){
                    result[i][j] = result[i][j-1] + result[i-1][j];
                }else if (i == 0 && j > 0 && j!=1){
                    result[i][j] = result[i][j-1];
                }else if (j == 0 && i > 0 && i!=1){
                    result[i][j] = result[i-1][j];
                }
        }
    }
      return result[m-1][n-1];
}
}

别人的写法,比较nb 

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

        //如果在起点或终点出现了障碍,直接返回0
        if (obstacleGrid[m - 1][n - 1] == 1 || obstacleGrid[0][0] == 1) {
            return 0;
        }

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

        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = (obstacleGrid[i][j] == 0) ? dp[i - 1][j] + dp[i][j - 1] : 0;
            }
        }
        return dp[m - 1][n - 1];
    }
}

343. 整数拆分

再写吧。。累了

96. 不同的二叉搜索树

416. 分割等和子集

背包问题 - 我真心实意的感觉这个像玄学

明明其实不太明白呢,但神不知鬼不觉的就写出来了,我的天,,,,,

为什么要求max呢????我真的不理解

class Solution {
    public boolean canPartition(int[] nums) {
        int sum =0;
        for (int  i =0;i < nums.length;i++){
            sum += nums[i];
        }
        if (sum % 2 != 0){
            return false;
        }else{
            sum = sum/2;
        }
        int dp[][] = new int[nums.length][sum + 1];
        for (int j = 0;j < sum + 1;j++){
            if (j >= nums[0]){
                dp[0][j] = nums[0];
            }
        }
        
        for (int i = 1;i < nums.length;i++){
            for (int j = 1;j < sum + 1;j++){
                if (j < nums[i]) 
                    dp[i][j] = dp[i - 1][j];
                else 
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]); 
            }
        }
        if(dp[nums.length - 1][sum] == sum){
        return true;
    }else{
        return false;
    }
    }
}

1049. 最后一块石头的重量 II 

这里使用了一维的数组来动态的更新所能承受的最大的重量,要点是要理解能不能把石头平均分为两份以换取最大值,并且在从0到sum/2的最大重量下,所可以放的重量的最大值,总体来说还是很难想的。。

第二个循环的j需要注意

最后的除也要注意一下

代码

class Solution {
    public int lastStoneWeightII(int[] stones) {

        int sum = 0;

        for (int i = 0;i < stones.length;i++){
            sum = sum + stones[i];
        }

        int total = sum;
        sum = sum/2;

        int dp[] = new int[sum+1];

        for (int i = 0;i < stones.length;i++){
            for (int j = sum; j >= stones[i];j--){
                dp[j] = Math.max(dp[j],dp[j - stones[i]]+stones[i]);
            }
        }

        int remind = total - 2 * dp[sum];
        return Math.abs(remind);

    }
}

494. 目标和 

这个题还不是很了解,继续加油吧

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for (int i = 0;i < nums.length;i++){
            sum +=nums[i];
        } 
        int left = (target + sum)/2;
        if ((target + sum) % 2 == 1 || Math.abs(target) > sum){
            return 0;
        }
        int dp[] = new int[left + 1];
        dp[0] = 1;
         for (int num : nums) { /
            for (int j = left; j >= num; j--) { 
                dp[j] += dp[j - num];
            }
        }
        return dp[left];
    }
}

dp[0] = 1;这个是为什么

ChatGPT

在这类动态规划问题中,dp[0] = 1;的设置是非常关键的。这里dp[0]表示的是在没有任何数字可选的情况下,和为0的方法数。即,不选择任何数字,就可以达成和为0的目标。这是基础情况(Base Case)。

为什么要将dp[0]设为1呢?这是因为在动态规划的过程中,我们利用之前计算的结果来计算当前的结果。当我们说dp[0] = 1时,我们实际上是在说:“如果没有数字可选(即子集为空),只有一种方式使得总和为0,那就是什么都不选。”

这个初始条件对于后续的递推非常重要。例如,当我们在计算dp[i](即和为i的方法数)时,如果当前考虑的数字为num,我们查看dp[i - num]的值(即在不包括当前数字的情况下,和为i - num的方法数)。dp[0] = 1保证了在递推开始的时候,我们有一个有效的起点。如果没有这个基础情况,那么递推就无从开始,因为我们总需要一个起始的参考点。

在这个特定问题中,我们使用dp数组来记录达到特定和的方法数量。因此,开始时设定dp[0] = 1,表示对于目标和为0,已经有了一种方法(即不选择任何元素)。这使得在动态规划过程中,每当我们考虑加入一个新的元素num时,都可以通过查看dp[之前的和]来更新dp[新的和],因为从dp[0]开始的这个基础上,我们可以建立起所有的解决方案。

474.一和零 

完全背包

518. 零钱兑换 II 

377. 组合总和 Ⅳ  

说实话我感觉背包问题我还是迷迷糊糊的,有一种一言难尽的感觉。

就是,总是感觉不得要领,最近状态不太好,估计还要再做几遍。

class Solution {
    public int combinationSum4(int[] nums, int target) {

        int dp[] = new int[target + 1];
        dp[0] = 1;
        for (int i = 0 ;i <= target ;i++){
            for (int j = 0;j < nums.length;j++){
                if (i >= nums[j]){
                dp[i] = dp[i] + dp[i-nums[j]];
                }
                
            }
        }
        return dp[target];
    }
}

因此这里暂时把后续的背包问题跳过一下,要不然太痛苦了。

打家劫舍问题

问题三还没有解决,有时间来总结一下

买卖股票的问题

感觉这个解释的很好

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值