动态规划详解

动态规划详解

一、什么是动态规划?

官方解释:动态规划(Dynamic Programming)是一种解决多阶段决策问题的数学优化方法。它通常用于在给定约束条件下,通过将原问题分解为多个子问题,并根据子问题的解构建出原问题的解。

up认为:动态规划就是将大问题变成小问题的解题方式,
动态规划基础题:斐波那契,爬楼梯等类问题
动态规划经典题:背包问题,打家劫舍,股票问题等
动态规划进阶题:子序列,求最值等问题。
对应在leetcode上有对应的题目。

二、动态规划分五步走

  1. 确定dp数组的含义 必须了解dp数组以及下标的含义
  2. 确定dp数组递推公式
  3. dp数组的初始化
  4. dp数组遍历顺序:很重要!!!!
  5. 打印dp数组:不是必须,如果答案错误,需要打印出来判断思路逻辑是否正确。

三,例题+ 讲解

在这里插入图片描述

class Solution {
    public int climbStairs(int n) {
        //处理特殊条件
        if(n==1 || n==2){
            return n;
        }
        //确定dp数组,以及下标的含义,res[i]表示在第i阶有几种方法
        int[] res = new int[n+1];
        //dp数组的初始化
        res[1] = 1;
        res[2] = 2;
        //dp数组的递推公式:res[i] = res[i-1]+res[i+1]
        //dp数组的遍历顺序,从第三阶开始
        for(int i=3;i<n+1;i++){
            res[i] = res[i-1]+res[i-2];
        }
        //表示爬上第n阶有res[n]种方法
        return res[n];
    }
}

在这里插入图片描述

class Solution {
    public int uniquePaths(int m, int n) {
        // 规定只能向下走和想右走,i+1,j+1
        // 1,dp数组的含义==========>表示dp[i]第i哥位置上有几条路径
        // 2,dp数组的地推公式======>dp[i][j] = dp[i][j-1]+dp[i-1][j]
        // 3,dp数组初始化==========>dp[0][0] = 0;dp[0][1] = 1;dp[1][0] = 1
        // 4,dp数组的遍历顺序
        // 5,打印dp数组来验证程序
        if(m==1 || n==1){
            return 1;
        }
        int[][] dp = new int[m][n];
        dp[0][0] = 0;
        dp[0][1] = 1;
        dp[1][0] = 1;
        for(int i=1;i<m;i++){
            dp[i][0] = 1;
            for(int j=1;j<n;j++){
                dp[0][j] = 1;
                dp[i][j] = dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
}

在这里插入图片描述

class Solution {
    public boolean isMatch(String s, String p) {
        if (s == null || p == null) {
            return false;
        }
        
        // 创建一个二维数组用于存储匹配结果
        boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];
        dp[0][0] = true; // 两个空字符串是匹配的

        // 初始化 p 的模式串匹配空字符串 s 的情况
        // 当 p 的字符为 '*' 时,可以将该字符和前一个字符一起忽略,因此 dp[0][i] 的值与 dp[0][i-2] 相同
        for (int i = 1; i <= p.length(); i++) {
            if (p.charAt(i - 1) == '*') {
                dp[0][i] = dp[0][i - 2];
            }
        }

        // 递推公式
        // 根据动态规划的思想,计算 dp[i][j] 的值,表示 s 的前 i 个字符与 p 的前 j 个字符是否匹配
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 1; j <= p.length(); j++) {
                if (p.charAt(j - 1) == '*') {
                    // 当 p 的当前字符为 '*' 时,可以选择忽略 '*' 和它前面的字符,或者匹配 s 的当前字符
                    dp[i][j] = dp[i][j - 2]; // 忽略 '*' 和它前面的字符
                    if (p.charAt(j - 2) == s.charAt(i - 1) || p.charAt(j - 2) == '.') {
                        // 如果 p 的前一个字符与 s 的当前字符相等,或者 p 的前一个字符为 '.',可以选择匹配 s 的当前字符
                        dp[i][j] = dp[i][j] || dp[i - 1][j];
                    }
                } else {
                    // 当 p 的当前字符不为 '*' 时,只有当 p 的当前字符与 s 的当前字符相等,或者 p 的当前字符为 '.',才能匹配
                    dp[i][j] = (p.charAt(j - 1) == s.charAt(i - 1) || p.charAt(j - 1) == '.') && dp[i - 1][j - 1];
                }
            }
        }
        
        // 返回最终的匹配结果
        return dp[s.length()][p.length()];
    }
}

总结

总的来说,动态规划需要对题目的深度了解透彻,以及对数据规律的判断。
可能看完之后还是有疑惑,建议对以上三题细细研究,动态规划的五步走要深深的理解。
感谢您的观看。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值