动态规划算法

一、前言

Q:什么是动态规划?
A:动态规划是将复杂的问题分解成更简单的子问题,并且记录中间计算结果的算法。
Q:哪些问题可以用动态规划解决?
A: 计数问题,比如求解有多少种问题的解决方案。求最大最小值,比如最长上升子序列长度,规划处一条权重最大的路径。求存在性,比如是否存在k数之和为sum。
Q:为什么不用递归?(动态规划优势)
A:递归中存在大量的重复计算,导致很高的时间复杂度。

二、动态规划思路

1.将原问题划分为若干阶段,每个阶段对应若干个子问题,提取这些子问题的特征(称之为 状态)。
2.寻找每一个状态的可能决策,或者说是各状态间的相互转移方式(用数学的语言描述就是 状态转移方程)。可以理解成子问题之间的依赖关系,当前状态依赖于前一个状态,并且考虑是如何得到最新状态的。
3.确定边界条件。考虑初始状态或者结束条件。
4.按顺序求解每一个阶段的问题。

三、解题

leecode 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 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/house-robber

思路:
首先思考只有一间房子时,只能选择取。
当有两间房子时,由于不能偷连续的两间房子,所以自然选择金额更高的一家,即Math.max(第一家,第二家)。
当超过两家之后,如第i间房子,偷或者不偷取决于两个因素

(1)前一家是否被偷;(2)第i家是否值得偷。

可以明确的是第i间房子只有两种状态,偷或者不偷。

偷:第i-1间不偷,金额为第i-2间+第i间。
不偷:仍等于第i-1间金额,没有增长。

可以推理转移方程:
dp[i]=max(dp[i−2]+nums[i],dp[i−1])

边界条件:
dp[0]=nums[0]
dp[1]=max(nums[0],nums[1])

只有一间房屋,则偷窃该房屋
只有两间房屋,选择其中金额较高的房屋进行偷窃

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

四、总结

动态规划题目很多,可以很难也可以很简单,关键在于对问题的分析分解。找出状态转移方程和边界条件问题基本上就解决一半,在练习时,多自己思考状态转移方程,就像数学公式一样,理解起来很容易,但是推导起来并不简单。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值