• 算法之动态规划(一)


    动态规划

    动态规划题目的特征
    1.重叠子问题(Overlapping Subproblems):这意味着在递归算法中,相同的子问题被多次求解。动态规划通过存储子问题的解,避免了重复计算,从而提高效率。
    2.最优子结构(Optimal Substructure):一个问题的最优解包含其子问题的最优解。这意味着,如果我们能够找到每个子问题的最优解,我们就能构建出整个问题的最优解。

    步骤:

    1.定义状态:
    确定dp数组的含义,dp[i]通常表示某个状态的值,例如,到达第i天的最大金子数量、到达第i个节点的最短路径长度等。
    2.确定状态转移方程
    根据问题的特点,找出状态之间的关系,即如何从一个或多个已知状态推导出新的状态值。
    3.确定初始状态和边界条件:
    设置dp数组的初始值,这通常是问题的基本情形,例如,dp[0] = 0。
    4.确定遍历顺序:
    根据问题的特点,确定是自顶向下还是自底向上的遍历顺序,以及如何更新dp数组。
    5.填充dp数组:
    根据状态转移方程,按照确定的遍历顺序填充dp数组。
    6.构造最优解:
    根据dp数组的结果,构造问题的最优解。
    通常结合记忆化搜索减少动态规划的时间复杂度!!! 记忆化的数组有一个条件是不能和数组初始化的数值一样不然容易造成混淆!!!

    70. 爬楼梯

    在这里插入图片描述
    首先写出递归出口当i<=1时,只有一种方案
    这里的memo数组是起到记忆化搜索的功能,防止重复计算
    dp[i]=dp[i-1]+dp[i-2];
    加入memo数组的话递归的子结构函数:memo[i]=dfs(i-1,memo)+dfs(i-2,memo)

    class Solution {
        public int climbStairs(int n) {
            int[] memo=new int[n+1];
            return dfs(n,memo);
        }
        int dfs(int i,int[] memo){
            if(i<=1)return 1;
            if(memo[i]!=0)return memo[i];
            return memo[i]=dfs(i-1,memo)+dfs(i-2,memo);
        }
    }
    

    198. 打家劫舍
    在这里插入图片描述
    和上一题的解法一样

    class Solution {
        private int[] nums,memo;
        public int rob(int[] nums) {
            this.nums=nums;
            int n=nums.length;
            memo=new int[n];
            Arrays.fill(memo,-1);
            return dfs(n-1);
        }
        private int dfs(int i) {
            if (i < 0) { // 递归边界(没有房子)
                return 0;
            }
            if (memo[i] != -1) { // 之前计算过
                return memo[i];
            }
            int res=Math.max(dfs(i-1),dfs(i-2)+nums[i]);
            return memo[i]=res;
        }
    }
    

    2320. 统计放置房子的方式数
    在这里插入图片描述
    只算一侧,算完一侧之后相乘就算两侧的房子个数

    class Solution {
        public int countHousePlacements(int n) {
            final int MOD = 1000000007;
            int[] dp = new int[n + 1];
            dp[0] = 1;
            dp[1] = 2;
            for (int i = 2; i <= n; i++) {
                dp[i] = (dp[i - 1] + dp[i - 2]) % MOD;
            }
            return (int) ((long) dp[n] * dp[n] % MOD);
        }
    }
    

    LCR 166. 珠宝的最高价值
    在这里插入图片描述
    首先定义一个状态数组dp[i][j]
    状态方程: dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]) + frame[i][j];当前网格线的值等于左侧或上侧的最大值最后加上当前网格线的值
    边界条件:只有一行dp[i][0] = dp[i-1][0] + frame[i][0];
    只有一列:dp[0][j] = dp[0][j-1] + frame[0][j];

    class Solution {
        public int jewelleryValue(int[][] frame) {
             int m = frame.length;
            int n = frame[0].length;
            int[][] dp = new int[m][n];
            dp[0][0] = frame[0][0];
            for(int i=1; i<m; i++){
                dp[i][0] = dp[i-1][0] + frame[i][0];
            }
            for(int j=1; j<n; j++){
                dp[0][j] = dp[0][j-1] + frame[0][j];
            }
            for(int i=1; i<m; i++){
                for(int j=1; j<n; j++){
                    dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]) + frame[i][j];
                }
            }
            return dp[m-1][n-1]; 
        }
    }
    

    63. 不同路径 II
    在这里插入图片描述
    容易想到状态转移方程:dp[i][j] =dp[i - 1][j] +dp[i][j - 1];(只有当前网格不是钻石的时候)
    边界条件:只有一行dp[i][j] = dp[i][j - 1];只有一列:dp[i][j] =dp[i - 1][j];

    class Solution {
        public int uniquePathsWithObstacles(int[][] obstacleGrid) {
            int m=obstacleGrid.length,n=obstacleGrid[0].length;
            int[][] dp=new int[m][n];
            dp[0][0]=obstacleGrid[0][0]==1?0:1;
            for(int i=0;i<m;i++){
                for(int j=0;j<n;j++){
                    if (obstacleGrid[i][j] != 1) {
                        if (i > 0 && j > 0) {
                            dp[i][j] =dp[i - 1][j] +dp[i][j - 1];
                        } else if (i > 0) {
                            dp[i][j] =dp[i - 1][j];
                        } else if (j > 0) {
                            dp[i][j] = dp[i][j - 1];
                        }
                    }
                }
            }
            return dp[m-1][n-1];
        }
    }
    
  • 相关阅读:
    react倒计时功能
    项目进度管理
    高程复习 欧几里得算法和扩展欧几里得算法考试前冲刺简约版
    希望所有计算机学生能看到这篇c语言教程
    亚马逊 sp-api更新库存 feed 方式,xsd 验证xml
    (73)MIPI DSI LLP介绍(十三)
    微信 小程序应用,页面,组件的生命周期
    机器学习笔记只隐马尔可夫模型(三)求值问题——前向算法(Forward Algorithm)
    PTA 7-231 买文具
    Github标星51K!阿里P8熬了700个小时,终于肝出32W字Java面试手册
  • 原文地址:https://blog.csdn.net/w287586/article/details/143359961