动态规划专题

LeetCode 70

https://leetcode.com/problems/climbing-stairs/

 


算法思路:

  1. 设置递推数组dp[0…n],dp[i]代表到达第i阶,有?走法,初始化数组为0
  2. 设置到达第1阶,有1种走法,到达第2阶有2种走法
  3. 利用i循环递推从第三阶到第n阶结果:

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]


动态规划原理

  1. 确认原问题与子问题
  2. 确认状态
  3. 确认边界状态的值
  4. 确定状态转移方程

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] dp[i]=dp[j]+1
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]

你可能感兴趣的:(数据结构与算法)