动态规划之硬币问题/迷宫问题/最大数组子序列和

 其实动态规划对于我最难的是边界问题

目录

1.动态规划四部曲:

迷宫问题

最大数组子序列和问题

单词拆分

动态规划之最长回文子串

309. 最佳买卖股票时机含冷冻期


1.动态规划四部曲:

1.确定状态,确定从什么时候开始,就是amout

2.确定转移方程,也就是 if (coins[j] <= i) {
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);//变成子问题,问题规模缩小
                }

3.确定初始条件和边界条件,也就是前面和后面几步

4.确定步数和尝试次数,也就是i和j的范围

class Solution {
    public int coinChange(int[] coins, int amount) {
        int max = amount + 1;//设置max填充dp数列,为之后的边界问题做铺垫
        int[] dp = new int[amount + 1];//定义dp长度,因为dp是从1开始,所以需要多一格
      
        Arrays.fill(dp, max);//填充数列
       
        dp[0] = 0;//dp[0]设置值,为特殊情况做准备
      
        for (int i = 1; i <= amount; i++) {//一步步递进
            for (int j = 0; j < coins.length; j++) {
                if (coins[j] <= i) {
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);//变成子问题,问题规模缩小
                }
            }
        }
        return dp[amount] > amount ? -1 : dp[amount];//判断是否正好组成总金额
    }
}

迷宫问题

class Solution {
    public int uniquePaths(int m, int n) {
        int dp[][]=new int[m][n];
        for(int i=0;i<n;i++){
            //先设置零行的路径方法都为1
            dp[0][i]=1;
        }
        for(int i=0;i<m;i++){
            //零列的路径方法也都为1,如此设置是防止后面的数组溢出,也就是设置边界条件
            dp[i][0]=1;
        }
        if(m==0&&n==0){
            return 0;
        }
        for (int i=1;i<m;i++){//设置i和j的边界

            for (int j = 1; j <n ; j++) {

                dp[i][j]=dp[i-1][j]+dp[i][j-1];//核心方程式,与斐波那契数列相似
            }
        }
        return dp[m-1][n-1];


    }
}

最大数组子序列和问题

class Solution {
    public int maxSubArray(int[] nums) {
        int[] dp = new int[nums.length];
       
        dp[0] = nums[0];
       
        int max = dp[0];
       
     for(int i=1;i<nums.length;i++){
       
         dp[i]=Math.max(dp[i-1]+nums[i],nums[i]);
       
         max=Math.max(max,dp[i]);
     }
     return max;
}
}

类似于上题,也是在之前走过的地方进行标记,从而免去一系列重复的计算,将单词分成各个部分,逐步确认能否拆分,如果一部分能拆分,则将其置为True

单词拆分

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        // 可以类比于背包问题
        int n = s.length();
        // memo[i] 表示 s 中以 i - 1 结尾的字符串是否可被 wordDict 拆分

       //个人感觉像记忆化搜索,对所走的路进行标记
        boolean[] memo = new boolean[n + 1];
        
        memo[0] = true;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < i; j++) {
                //memo[j]为true表明之前的都已经匹配上了
                if (memo[j] && wordDict.contains(s.substring(j, i))) {
                    memo[i] = true;
                    break;
                }
            }
        }
        return memo[n];
    }
}

动态规划之最长回文子串

 设置起点为start,设置终点为END,如何判断起点为Start,终点为END的字符串是回文子串呢,设计标记数组arr,只要arr[start+1][end-1]为true,即子串是回文子串,并且两端的字符一样,就表示是回文子串,同时要考虑边界条件,字符串为2个或者3个的情况下,判读是否为回文子串,在长度为2或3时,只需要判断两端字符是否相等即可。用到了动态规划的思想,将问题规模一步步化简。

class Solution {
      public String longestPalindrome(String s) {
        boolean arr[][]=new boolean[s.length()][s.length()];
        if(s.length()==1){
            return s;
        }
        int max=0;
        int Start=0;
        int End=0;
        for(int right=1;right<s.length();right++){
            for (int left=0;left<right;left++){
                if (s.charAt(left)==s.charAt(right)&&(right-left<=2||arr[left+1][right-1])){
                    arr[left][right]=true;
                    if(max<right-left+1){
                        Start=left;
                        End=right;
                        max=End-Start+1;
                    }
                }
            }
        }
        return s.substring(Start,End+1);

    }
}

309. 最佳买卖股票时机含冷冻期

这题将dp定义了四种状态

1.日期

2.持股

3.不持股

4.在冷冻期(即上一天卖出股票)

通过对状态的分析,求出各个的局部最优解,最终得到最优解

class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }
        //由于可以无限次交易,所以只定义两个维度,第一个维度是天数,第二个维度表示是否持有股票,0表示不持有,1表示持有,2表示过渡期
        int[][] dp = new int[prices.length][3];
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        dp[0][2] = 0;
        for (int i = 1; i < prices.length; i++) {
            //第i天不持有股票的情况有两种
            //a.第i-1天也不持有股票
            //b.第i-1天是过渡期
            dp[i][0] = Math.max(dp[i-1][0], dp[i-1][2]);
            //第i天持有股票有两种情况
            //a.第i-1天也持有股票,第i天不操作,
            //b.第i-1天不持有股票,在第i天买入
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i]);
            //第i天是冷冻期只有一种情况,第i-1天持有股票且卖出
            dp[i][2] = dp[i-1][1] + prices[i];
        }
        //最后最大利润为最后一天,不持有股票或者进入冷冻期的情况
        return Math.max(dp[prices.length-1][0], dp[prices.length-1][2]);
    }
}

树形DP

树形DP便是维护两个状态数组,分别为left[]和right[],表示左子节点和右子节点,数组中又存放状态,在此题中,存放小偷偷或者不偷两种状态,采取后续遍历,用动态规划进行求解。这里的动态规划采取了递归的形式。

class Solution {
      // 3.状态标记递归
    // 执行用时:0 ms , 在所有 Java 提交中击败了 100% 的用户
    // 不偷:Max(左孩子不偷,左孩子偷) + Max(又孩子不偷,右孩子偷)
    // root[0] = Math.max(rob(root.left)[0], rob(root.left)[1]) +
    // Math.max(rob(root.right)[0], rob(root.right)[1])
    // 偷:左孩子不偷+ 右孩子不偷 + 当前节点偷
    // root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val;
    public int rob(TreeNode root) {
        int[] res = robAction1(root);
        return Math.max(res[0], res[1]);
    }

    int[] robAction1(TreeNode root) {
        //0表示不偷当前结点,1表示偷当前节点
        int res[] = new int[2];
        if (root == null)
            return res;

        int[] left = robAction1(root.left);
        int[] right = robAction1(root.right);
         //不偷当前节点
        res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
        //偷当前节点(当前节点+左右孩子不偷)
        res[1] = root.val + left[0] + right[0];
        return res;
    }
}

背包问题

背包问题的原型 他总结的非常好

代码随想录

总之背包类的动态规划问题,个人来是存在一个约束条件的。在典型背包中,他的约束条件是背包的容量,通过背包的容量,和物品的价值,通过两层for循环,逆序的求得背包所能取得物品的最大价值。

分割等和子集也是背包问题的变形 力扣题目链接

所要求的值为数组和的一半,那我们就以此为约束,抽象成背包的容量,求得在此容量下所能承载的最大价值,再对比约束条件,就能求得结果!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值