leetcode 解题启发 --动态规划

本文深入解析动态规划这一重要解题思想,通过爬楼梯与打家劫舍等LeetCode经典题目,详细阐述动态规划的特性、思路及应用。从状态转移方程到边界条件,逐步引导读者掌握动态规划的解题技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

leetcode 中另一个重要的解题思想–动态规划

动态规划是一种思想,不是具体的指某种算法,与分治法类似,通过拆分问题,定义问题状态和状态之间的关系,使问题能够以递推(分治)的方式去解决。

动态规划的特点:

  • 局部解 - 全部解
  • 局部解 - 最优解

动态规划的思路:

  • 将大问题分解为子问题
  • 状态转移方程
  • 边界情况

这里用一个具体的例子说明,leetcode70.爬楼梯

题目描述:
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。

示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

我们可以计算输入4:

示例 4:
输入: 4
输出: 5
解释: 有五种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶 + 1 阶
2.  1 阶  + 1 阶 + 2 阶
3.  1 阶 + 2 阶  + 1 阶
4.  2 阶 + 1 阶 + 1 阶 
5.  2 阶 + 2 阶

那么规律就是

in = 1、out = 1
in = 2、out = 2
in = 3、out = 3 (1+2)
in = 4、out = 5(2+3)

in = n、out = in(n-1) + in(n-2)

这里可以看出,在第n个的值是由n-1 和 n-2的结果相加的(斐波那契数列),最后一个就是要得到的状态转换方程,所以思路就有了,大问题n是由于n-1和n-2解决的,3是由2和1解决的,就是累加嘛,状态转换方程:in = n、out = in(n-1) + in(n-2),边界条件 n,所以代码可以这样写:

public int climb(int n) {
    	int[] dp = new int[n+1];
    	dp[1] = 1;
    	dp[2] = 2;
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i-1] + dp[i-2];
        }
        return dp[n];
    }

这个例子比较直观,下面例子的思路也是动态规划,但是加了一些限制:

198.打家劫舍
题目描述:

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你**在不触动警报装置的情况下,**能够偷窃到的最高金额

示例 1:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。
     
示例 2:
输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

这里多了一个考虑的部分,相邻两个数不能同时取

  • 如果数组只有两个数,那我们就得知道第一个与第二个比较,取大的;
  • 如果数组只有三个数,那我们就得知道第一个加第三个的和与第二个比较,取大的;
  • 如果数组只有四个数,那我们就得知道第四个加第二个之前的最大值的和与第三个之前的最大值比较,取大的

代码如下:

    public int rob(int[] nums) {
        //异常情况
        if (nums == null || nums.length == 0) {
            return 0;
        }
        //特殊情况
        if (nums.length == 1) {
            return nums[0];
        }
        
        int[] dp = new int[nums.length];
        //第一个默认最大
        dp[0] = nums[0];
        //每两个元素之间取大的
        dp[1] = Math.max(nums[0], nums[1]);
        //遍历
        for (int i = 2; i < nums.length; i++) {
            dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[nums.length - 1];
    }

leetcode中按照动态规划求解的题型代表还有如下:

  • 279.完全平方数
  • 309.最佳买卖股票时期含冷冻期
  • 312.戳气球
  • 337.打家劫舍Ⅲ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值