LeetCode 70
https://leetcode.com/problems/climbing-stairs/
算法思路:
dp[0]=0
dp[1]=1
dp[2]=2
dp[3]=dp[1]+dp[2]=3
…
dp[i]=dp[i-1]+dp[i-2]
…
dp[n]=dp[n-1]+dp[n-2]
代码实现:
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
dp=[0 for _ in range(n+3)]
dp[1]=1
dp[2]=2
for i in range(3,n+1):
dp[i]=dp[i-1]+dp[i-2]
return dp[n]
动态规划原理
leetcode 198
https://leetcode.com/problems/house-robber/
算法思路:
1. 确认原问题与子问题
原问题为求n个房间最优解,子问题为求求前1个房间,前2个房间…前n-1个房间的最优解
2.确认状态
第i个状态即为前i个房间能够获得的最大财宝
3.确认边界状态的值
前1个房间的最优解,第一个房间的财宝
前2个房间的最优解,第1,2个房间的最优解
4.确定状态转移方程
a选择第i个房间:第i个房间+前2个房间的最优解
b不选择第i个房间:前i-1个房间的最优解
转移方程:dp[i]=max(dp[i-1],dp[i-2]+nums[i])(i>=3)
class Solution(object):
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n=len(nums)
if n==0:
return 0
if n==1:
return nums[0]
dp=[0 for _ in range(n)]
dp[0]=nums[0]
dp[1]=max(nums[0],nums[1])
for i in range(2,n):
dp[i]=max(dp[i-1],dp[i-2]+nums[i])
return dp[n-1]
leetcode53
https://leetcode.com/problems/maximum-subarray/
算法思路:
将求n个数的数组的最大字段和,转换为分别求出以第一个,第2个…第i个、第n个数字结尾的最大字段和,再找出n个结果中最大的
第I个状态(dp[i])即为以第I个数字结尾的最大子段和(最优解)。由于以第i-1个数字结尾的最大子段和(dp[i-1])和nums[i]相邻:
若dp[i-1]>0:
dp[i]=dp[i-1]+nums[i]
否则:dp[i]=nums[i]
边界值:dp[0]=nums[0]=-2
dp[1]=max(dp[0]+nums[1],nums[1])
dp[2]=max(dp[1]+nums[2],nums[2])
…
dp[i]=max(dp[i-1]+nums[i],nums[i])
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n=len(nums)
dp=[0 for _ in range(n+1)]
dp[0]= nums[0]
max_res=dp[0]
for i in range(1,n):
dp[i]=max(dp[i-1]+nums[i],nums[i])
if max_res < dp[i]:
max_res=dp[i]
return max_res
leetcode 322
https://leetcode.com/problems/coin-change/
算法思路:
dp[i]代表金额i的最优解(即最小使用张数)
dp[]存储金额1到14的最优解
状态i可由状态i-1,i-2,i-5,i-7,i-10,5个状态转移到,故
dp[i]=min(dp[i-1],dp[i-2],dp[i-5],dp[i-7],dp[i-10])+1
coins={1,2,5,7,10}
设dp[0]=0
dp[1]=1+dp[0]
dp[2]=1+dp[0]
dp[5]=1+dp[0]
dp[7]=1+dp[0]
dp[10]=1+dp[0]
此外:
dp[3]=1+dp[2]
dp[4]=1+dp[3]=1+dp[2]
dp[4]=getmin(dp[3],dp[2])+1
dp[6]=getmin(dp[5],dp[4],dp[1])+1
…
dp[14]=getmin(dp[13],dp[12],dp[9],dp[7],dp[4])+1
设i 代表金额,coins[j]代表第j个面值的金额
当i-coins[j]>=0且dp[i-coins[j]]!=-1时:
j=0,1,2,3,4;coins[j]=1,2,5,7,10
dp[i]=getmin(dp[i-coins[j]])+1
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
dp=[-1 for _ in range(amount+1)]
dp[0]=0
for i in range(1,amount+1):
for j in range(len(coins)):
if i-coins[j]>=0 and dp[i-coins[j]]!=-1:
if dp[i]==-1 or dp[i] > dp[i-coins[j]]+1:
dp[i]=dp[i-coins[j]]+1
return dp[amount]
leetcode 120
https://leetcode.com/problems/triangle/
算法思路:
1设置一个二维数组,最优值三角形dp[][],并初始化数组元素为0
dp[i][j]代表从底向上递推时,走到三角形第i行第j列的最优解
2从三角形底面向三角形上方进行动态规划
a边界条件:底面上的最优值即为三角形最后一层
b利用I循环,从倒数第二层递推至第一层,对于每层各列,进行动态规划递推
第I行,第J列的最优解为dp[i][j],可达到(I,j)的两个位置的最优解为dp[i+1][j],dp[i+1][j+1]: dp[i][j]=min(dp[i+1][j],dp[i+1][j+1])+traingle[i][j]
3.返回dp[0][0]
leetcode300
https://leetcode.com/problems/longest-increasing-subsequence/
算法思路:
1设置动态规划数组dp[],第I个状态代表以第I个元素结尾的最长上升子序列的长度
2动态规划边界:dp[0]=1
初始化最长上升子序列的长度LIS=1
从1到n-1,循环I,计算dp[i]:
从0到i-1,循环j,若nums[i]>nums[j],说明nums[i]可放置在nums[j]的后面,组成最长上升子序列:
若dp[i]
LIS为dp[0],dp[1]…dp[i]…dp[n-1]中最大的
class Solution(object):
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n=len(nums)
if n==0:
return 0
dp=[0 for _ in range(n+1)]
dp[0]=1
LIS=1
for i in range(n):
dp[i]=1
for j in range(i):
if nums[i]>nums[j] and dp[i] < dp[j] + 1:
dp[i]=dp[j]+1
if LIS
leetcode 64
https://leetcode.com/problems/minimum-path-sum/
算法思路:
设dp[i][j]为到达位置(i,j)时的最优解(最小值)
dp[i][j]与dp[i-1][j]、dp[i][j-1]、grid[i][j]关系是:
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j]
class Solution(object):
def minPathSum(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
m,n=len(grid),len(grid[0])
dp=[[0 for _ in range(n)] for _ in range(m)]
dp[0][0]=grid[0][0]
for i in range(1,m):
dp[i][0]=dp[i-1][0]+grid[i][0]
for j in range(1,n):
dp[0][j]=dp[0][j-1]+grid[0][j]
for i in range(1,m):
for j in range(1,n):
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j]
return dp[-1][-1]