什么类型的题可以思考动态规划
最值问题
- 最长上升子序列
计数问题
- 有多少种方式走到右下角
- 有多少种方式选出k个数和是target
存在性问题
- 能不能选出k个数组成和是sum
动态规划的思考过程
- 1 原问题分解为子问题
- 2 确定状态
- 3 确定一些初始状态(边界状态)的值
- 4 确定状态转换方程,由已知推未知
- 5
递归到动规的转换过程
- 记录递归子问题的解,避免下次遇到相同的子问题需要重复计算
- 返回值相同
- 相当于递归的逆过程
- 从边界值开始,逐步填充动态dp数组,相当于递归的逆过程
42. 连续子数组的最大和
题目
输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
解题思路
用dp[i]表示以nums[i]结尾的连续子数组的最大和
则
if dp[i-1]+nums[i]>nums[i]:
dp[i]=dp[i-1]+nums[i]
else:
dp[i]=nums[i]
化简得:
if dp[i-1]>0:
dp[i]=dp[i-1]+nums[i]
else:
dp[i]=nums[i]
再次化简得
dp[i]=nums[i]+max(dp[i-1],0)
最终代码
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
ret=nums[0]
max_value=nums[0]
for i in range(1,len(nums)):
ret=nums[i]+max(ret,0)
if ret>max_value:
max_value=ret
return max_value
青蛙跳台阶问题
题目
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:2
示例 2:
输入:n = 7
输出:21
示例 3:
输入:n = 0
输出:1
提示:
0 <= n <= 100
解题思路
dp思路:
dp[i]=dp[i-1]+dp[i-2]
只有两种可能:在上一步的基础上走一步,或者在上上一步的基础上走两步
代码
class Solution:
def numWays(self, n: int) -> int:
a,b=1,1
for i in range(1,n):
a,b=b,a+b
return b % 1000000007
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 。
提示:
0 <= nums.length <= 100
0 <= nums[i] <= 400
解题思路
边界条件
当只有一间房屋的时候,直接添加;dp[i]=nums[0]
当有两间房屋的时候,挑选其中的最大值;dp[i]=max(nums[0],nums[1])
迭代条件
dp[i]=max(dp[i-2]+nums[i],dp[i-1])
当选择第j间房子的时候,则不能选择第j-1间房间,最大金额为dp[i]=dp[i-2]+nums[i]
当不选择第j房间的时候,最大金额为dp[i]=dp[i-1]
代码
if not nums:
return 0
if len(nums)==1:
return nums[0]
dp=[0]*len(nums)
#边界条件
dp[0]=nums[0]
dp[1]=max(nums[0],nums[1])
#迭代
for i in range(2,len(nums)):
dp[i]=max(dp[i-1],dp[i-2]+nums[i])
return dp[-1]
股票买卖问题
题目
- 买卖股票的最佳时机 II
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
提示:
1 <= prices.length <= 3 * 10 ^ 4
0 <= prices[i] <= 10 ^ 4