【动态规划】刷题记录
什么是动态规划
百度百科解释如下:
动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。
动态规划算法的基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。
基本思想与策略编辑:
由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。
一篇动态规划 博客 阐述如下:
首先是拆分问题,根据问题的可能性把问题划分成一步一步,这样就可以通过递推或者递归来实现.
关键就是这个步骤,动态规划有一类问题就是从后往前推到,有时候我们很容易知道:如果只有一种情况时,最佳的选择应该怎么做。然后根据这个最佳选择往前一步推导,得到前一步的最佳选择
然后就是定义问题状态和状态之间的关系,我的理解是前面拆分的步骤之间的关系,用一种量化的形式表现出来,类似于高中学的推导公式,因为这种式子很容易用程序写出来,也可以说对程序比较亲和(也就是最后所说的状态转移方程式)
我们再来看定义的下面的两段,我的理解是比如我们找到最优解,我们应该讲最优解保存下来,为了往前推导时能够使用前一步的最优解,在这个过程中难免有一些相比于最优解差的解,此时我们应该放弃,只保存最优解,这样我们每一次都把最优解保存了下来,大大降低了时间复杂度。
动态规划与分治法的区别在于划分的子问题是有重叠的,解过程中对于重叠的部分只要求解一次,记录下结果,减少了重复计算过程。
另外,DP在求解一个问题最优解时,不是固定的计算合并某些子问题的解,而是根据各子问题的解的情况选择其中最优的。
动态规划求解具有以下性质:
最优子结构性质:最优解包含了其子问题的最优解,不是合并所有子问题的解,而是找最优的一条解线路,选择部分子最优解来达到最终的最优解。
子问题重叠性质:先计算子问题的解,再由子问题的解去构造问题的解(由于子问题存在重叠,把子问题解记录下来为下一步使用,这样就可以从备忘录中读取)。其中备忘录先记录初始状态。
刷题记录
最长递增子序列
描述
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:
1 | 输入:nums = [10,9,2,5,3,7,101,18] |
LeetCode 链接:https://leetcode.cn/problems/longest-increasing-subsequence
思路
令状态 dp[i] 表示以 nums[i] 作为末尾的最长递增子序列的长度,考虑边界情况,dp[0] = 1,状态转移方程 dp[i] = max(dp[j]) +1,其中 0<=j<i 且 num[j]<num[i]
,考虑在 j = 0…i-1 取一个最大子序列长度时,因为要求 num[i] 结尾,序列要求递增,则必须 num[i] > num[j]。
最后,整个数组的最长上升子序列即 dp 数组的最大值。
题解
1 | class Solution { |
最大连续子序列和
描述
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
1 | 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] |
LeetCode 链接:https://leetcode.cn/problems/maximum-subarray/
思路
令状态 dp[i] 表示以 nums[i] 作为末尾的连续序列的最大和,考虑边界情况,dp[0] = nums[0],状态转移方程 dp[i] = max(nums[i], dp[i-1] + nums[i]),因为是以 nums[i] 结尾,max 的作用其实就是取舍上一个状态,如果上一个状态小于等于 0,dp[i] = nums[i]。
求 dp[i] 的同时可以做比较,避免二次循环。
题解
1 | class Solution { |
买卖股票的最佳时机
描述
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
LeetCode 链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock
思路
如果我们真的在买卖股票,我们肯定会想:如果我是在历史最低点买的股票就好了!太好了,在题目中,我们只要用一个变量记录一个历史最低价格 minprice,我们就可以假设自己的股票是在那天买的。那么我们在第 i 天卖出股票能得到的利润就是 prices[i] - minprice。
因此,我们只需要遍历价格数组一遍,记录历史最低点,然后在每一天考虑这么一个问题:如果我是在历史最低点买进的,那么我今天卖出能赚多少钱?当考虑完所有天数之时,我们就得到了最好的答案。
LeetCode-Solution 链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/solution/121-mai-mai-gu-piao-de-zui-jia-shi-ji-by-leetcode-/
题解
1 | class Solution { |
卖股票的最佳时机 II
UVA 12034 Race
描述
n 匹马,共有多少种排名情况(可以并列)
UVA 链接:https://vjudge.net/problem/UVA-12034
思路
参考链接:https://blog.csdn.net/qq_39479426/article/details/81229724
dp[i][j]
表示 i 匹马占有 j 个名次的组合情况
然后考虑 i 匹马和 i-1 匹马的转移关系,多了一匹马要放在哪个位置,有下面两种情况
第 i 匹马和前 i-1 匹马中至少一匹马的成绩相同(j 个名次就有 j 种情况)
这匹马独占了一个成绩(可以放入 j 个位置,注意这里不是 j+1)
所以可以得到递推式:dp[i][j] = dp[i-1][j] * j + dp[i-1][j-1] * j
题解
1 |
|
0/1 背包问题
描述
给定 n 种物品和一个容量为 C 的背包,物品 i 的重量是 wi,其价值为 vi。问:应该如何选择装入背包的物品,使得装入背包中的物品的总价值最大?
题解
1 |
|
参考材料
1、北京大学郭炜 MOOC 慕课:https://www.icourse163.org/learn/PKU-1001894005