动态规划-初级
Posted AI前行之路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划-初级相关的知识,希望对你有一定的参考价值。
0. 动态规划的基本思路
动态规划的主要步骤包括三个:
1、构建dp数组(1-d、multi-d)/矩阵等,用于表示当前最优的信息。
2、构建状态转移矩阵。主要目的是用于更新dp数组/矩阵的信息。
3、初始化dp状态。
大多数题目,三部曲走一走就出来了。难点一般在于dp数组/矩阵的构建,需要对信息有一个敏感的把控。
1. 入室盗窃问题
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
Example 1:
Input: nums = [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). Total amount you can rob = 1 + 3 = 4.
Example 2:
Input: nums = [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1). Total amount you can rob = 2 + 9 + 1 = 12.
Constraints:
0 <= nums.length <= 100
0 <= nums[i] <= 400
分析:该问题的本质就是给定一个list,从中取数字并求和,不能取相邻的数字,求能得到的最大值。利用dp方法,构建dp数组,其中dp[i]表示到第i家时的最大收益,状态转移方程为:dp[i]=max(dp[i-2]+nums[i],dp[i-1]),即当前的数字加上前两个的最大收益并与前一个的最大收益进行比较,保留最大值。
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums)<=2:return max(nums)
dp=[0,nums[0]]
for i in range(2,len(nums)):
dp[i]=max(dp[i-2]+nums[i-1],dp[i-1])
return max(dp[-2:)
为了节约空间复杂度,可以不构建dp数组,因为每次状态转移时只用到了前两个值,可以直接用两个变量进行表示,不断更新两个变量即可。
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums)<1:return 0
prev1=0
prev2=0
for num in nums:
prev1,prev2=max(num+prev2,prev1),prev1
return prev1
2. 斐波那契问题
分解之后:可以得知,n个台阶的上法为F(N)种,其结果F(N)=F(N-1)+F(N-2)。因为上n个阶梯之前,只有两种情况,一种是还有一层可以上,一种是还有两层阶梯可以上。
逐次分解,得到F(3)=F(2)+F(1),其中F(1)=1,F(2)=2为初始化的解,通过这几个初始解,可以推广到情况为n时的结果。
class Solution:
def fibonacci(self,n):
a,b=1,1
for i in range(n):
a,b=b,a+b # 这个写法是两个计算并行处理 与 a=b b=a+b结果不同。
return a
3. 爬楼梯的最小消耗
On a staircaseOn a staircase, the i-th step has some non-negative cost cost[i] assigned (0 indexed). Once you pay the cost, you can either climb one or two steps. You need to find minimum cost to reach the top of the floor, and you can either start from the step with index 0, or the step with index 1.
Example 1:
Input: cost = [10, 15, 20]
Output: 15
Explanation: Cheapest is start on cost[1], pay that cost and go to the top.
Input: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
Output: 6
Explanation: Cheapest is start on cost[0], and only step on 1s, skipping cost[3].
Note:
cost will have a length in the range [2, 1000].
Every cost[i] will be an integer in the range [0, 999].
分析:
在阶梯中,第i个阶梯有一个非负的消耗cost[i]. 一旦你进行了消耗,可以选择走1步or2步。
求到顶部的最小消耗。
可以选择从index 0 or index 1 开始。
经典的动态规划题目,定义个dp[n],其中dp[i]表示走到当前阶梯时的最小消耗。
由于一次可以走1or2步,则当前阶梯的最小消耗可以是 2步前or1步前的最小消耗加上当前的消耗。
可知,动态转移矩阵为,dp[i]=min(dp[i-1]+cost[i],dp[i-2]+cost[i])
class Solution:
def minCostClimbingStairs(self, cost) -> int:
if len(cost)<=2:return min(cost)
dp=cost[:2]
for i in range(2,len(cost)):
dp.append(min(dp[i-1]+cost[i],dp[i-2]+cost[i]))
return min(dp[-2:])
以上是关于动态规划-初级的主要内容,如果未能解决你的问题,请参考以下文章