Hot100 动态规划

动态规划

动规五部曲:

  1. 确定dp数组以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

70. 爬楼梯 - 力扣(LeetCode)

爬到第一层楼梯有一种方法,爬到二层楼梯有两种方法。

那么第一层楼梯再跨两步就到第三层 ,第二层楼梯再跨一步就到第三层。

所以到第三层楼梯的状态可以由第二层楼梯 和 到第一层楼梯状态推导出来,那么就可以想到动态规划了。

我们来分析一下,动规五部曲:

定义一个一维数组来记录不同楼层的状态

  1. 确定dp数组以及下标的含义

dp[i]: 爬到第i层楼梯,有dp[i]种方法

  1. 确定递推公式

如何可以推出dp[i]呢?

从dp[i]的定义可以看出,dp[i] 可以有两个方向推出来。

首先是dp[i - 1],上i-1层楼梯,有dp[i - 1]种方法,那么再一步跳一个台阶不就是dp[i]了么。

还有就是dp[i - 2],上i-2层楼梯,有dp[i - 2]种方法,那么再一步跳两个台阶不就是dp[i]了么。

那么dp[i]就是 dp[i - 1]与dp[i - 2]之和!

所以dp[i] = dp[i - 1] + dp[i - 2] 。

在推导dp[i]的时候,一定要时刻想着dp[i]的定义,否则容易跑偏。

java 复制代码
class Solution {
    public int climbStairs(int n) {
        if(n==1||n==2) return n;
        int[] dp=new int[n+1];
        dp[0]=1;
        dp[1]=1;
        //dp[2]应该是2
        dp[2]=2;
        for(int i=3;i<=n;i++)
        {
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
}

746. 使用最小花费爬楼梯 - 力扣(LeetCode)

题目没说明白,脑残的很

java 复制代码
class Solution {
    public int minCostClimbingStairs(int[] cost) {
        //这个题他爹的有毛病 cost的长度是n 但是楼梯下标要到n 长度为n+1 
        if(cost.length==2) return Math.min(cost[0],cost[1]);//只有1极楼梯
        int n=cost.length;
         //dp表示到达此处的最小花费
        int[] dp=new int[n+1];
       
        dp[0]=0;
        dp[1]=0;//因为可以选择从0或者1出发
        for(int i=2;i<=n;i++)
        {
            dp[i]=Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
        }
        return dp[n];
            }
}

63. 不同路径 II - 力扣(LeetCode)

和62不同路径一样 先初始化横竖两排,然后判断一下有障碍的地方dp就是0

java 复制代码
class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m=obstacleGrid.length;
        int n=obstacleGrid[0].length;
        int[][] dp=new int[m][n];
        //如果第一行或第一列中存在障碍物,那么障碍物之后的路径数量应该是0,而不是1。
        for(int i=0;i<obstacleGrid.length;i++)
        {
             if(obstacleGrid[i][0]==0)
            {
                dp[i][0]=1;
            }else{
                break;
            }
        }
        for(int j=0;j<obstacleGrid[0].length;j++)
        {
            if(obstacleGrid[0][j]==0)
            {
                dp[0][j]=1;
            }else{
                break;
            }
        }
        for(int i=1;i<m;i++)
        {
            for(int j=1;j<n;j++)
            {
                if(obstacleGrid[i][j]!=1)
                {
                    dp[i][j]=dp[i-1][j]+dp[i][j-1];
                }else{
                    dp[i][j]=0;
                }
                
            }
        }
        return dp[m-1][n-1];
    }
}

118. 杨辉三角 - 力扣(LeetCode)

java 复制代码
class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> res=new ArrayList<>();
        res.add(List.of(1));
        for(int i=1;i<numRows;i++)
        {
            List<Integer> row=new ArrayList<>(i+1);//i+1是元素数量
             //第一个是1
             row.add(1);
              for (int j = 1; j < i; j++) {
                // 左上方的数 + 正上方的数
                row.add(res.get(i - 1).get(j - 1) + res.get(i - 1).get(j));
            }
            //最后一竖是1
            row.add(1);
            res.add(row);
        }
       return res;
    }
}

**343. 整数拆分 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int integerBreak(int n) {
        //dp[i] 为正整数 i 拆分后的结果的最大乘积
        int[] dp = new int[n+1];
        dp[1]=1;
        dp[2]=1;
        for(int i = 3; i <= n; i++) {
            for(int j = 1; j < i;j++) {
               //如果在比较最大值的时候不包括dp[i],那有可能越比越小,倒把一开始找到的最大值给弄丢了
                dp[i] = Math.max(dp[i], Math.max(j*(i-j), j*dp[i-j]));
                // j * (i - j) 是单纯的把整数 i 拆分为两个数 也就是 i,i-j ,再相乘
                //而j * dp[i - j]是将 i 拆分成两个以及两个以上的个数,再相乘。
            }
        }
        return dp[n];
    }
}

198. 打家劫舍 - 力扣(LeetCode)

动态规划的的四个解题步骤是:

  • 定义子问题
  • 写出子问题的递推关系
  • 确定 DP 数组的计算顺序
  • 空间优化(可选)
java 复制代码
class Solution {
    public int rob(int[] nums) {
        if(nums.length==1) return nums[0];
        if(nums.length==2) return Math.max(nums[0],nums[1]);
        //只有两种状态 偷窃或者不偷窃
        int[] dp=new int[nums.length];
        //表示两种状态中最大获利
       dp[0]=nums[0];
    //    dp[1]=nums[1];不对哦
    dp[1]=Math.max(dp[0],nums[1]);
        //列出状态转移方程
        for(int i=2;i<nums.length;i++)
        {
            dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
        }
        return dp[nums.length-1];
    }
}

首先「完全平方数」有无限个,但要凑成的数字是给定的。

所以首先把所有可能用到的「物品」预处理出来。

从而将问题转换为:给定了若干个数字,每个数字可以被使用无限次,求凑出目标值n所需要用到的是最少数字个数是多少。

152. 乘积最大子数组 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int maxProduct(int[] nums) {
     
        int max = Integer.MIN_VALUE, imax = 1, imin = 1;

    for(int i=0; i<nums.length; i++){
            if(nums[i] < 0){ 
//由于存在负数,那么会导致最大的变最小的,最小的变最大的。因此还需要维护当前最小值imin 
//在出现负数这种危机关头计算最大最小
              int tmp = imax;
              imax = imin;
              imin = tmp;
            }
            imax = Math.max(imax*nums[i], nums[i]);//一旦前面有负数就放弃曾经的一切
            imin = Math.min(imin*nums[i], nums[i]);
            
            max = Math.max(max, imax);
        }
        return max;
    }
}
相关推荐
SylviaW0828 分钟前
python-leetcode 37.翻转二叉树
算法·leetcode·职场和发展
h^hh37 分钟前
洛谷 P3405 [USACO16DEC] Cities and States S(详解)c++
开发语言·数据结构·c++·算法·哈希算法
玦尘、37 分钟前
位运算实用技巧与LeetCode实战
算法·leetcode·位操作
重生之我要成为代码大佬44 分钟前
Python天梯赛10分题-念数字、求整数段和、比较大小、计算阶乘和
开发语言·数据结构·python·算法
Best_Me071 小时前
【CVPR2024-工业异常检测】PromptAD:与只有正常样本的少样本异常检测的学习提示
人工智能·学习·算法·计算机视觉
HBryce241 小时前
缓存-算法
算法·缓存
eso19832 小时前
Spark MLlib使用流程简介
python·算法·spark-ml·推荐算法
夏末秋也凉2 小时前
力扣-回溯-93 复原IP地址
算法·leetcode
Erik_LinX2 小时前
算法日记27:完全背包(DFS->记忆化搜索->倒叙DP->顺序DP->空间优化)
算法·深度优先
AC使者2 小时前
D. C05.L08.贪心算法入门(一).课堂练习4.危险的实验(NHOI2015初中)
算法·贪心算法