zoukankan      html  css  js  c++  java
  • 动态规划DP

    70. 爬楼梯

    You are climbing a stair case. It takes n steps to reach to the top.

    Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

    Example 1:

    Input: 2
    Output: 2
    Explanation: There are two ways to climb to the top.
    1. 1 step + 1 step
    2. 2 steps
    

    Example 2:

    Input: 3
    Output: 3
    Explanation: There are three ways to climb to the top.
    1. 1 step + 1 step + 1 step
    2. 1 step + 2 steps
    3. 2 steps + 1 step


    class Solution:
        def climbStairs(self, n: int) -> int:
            memo = [1,1]
            if n <= 2 :return n 
            for i in range(2,n+1):
                memo.append(memo[i-1] + memo[i-2])
            return memo[n]
    递推DP

    个人理解:

    暴力法时间2的n次,空间n:DFS设立终止条件当步数大于等于楼数返回,爬n层楼梯取决于n-1层和n-2层楼梯方法之和,爬n-1取决于n-2和n-3以此类推...爬2层楼梯的方法有2种,爬1层楼梯的方法有1种,返回结果;

    回溯 O(n):每次记录层数的值并传递到下一层,可以节省重复计算的时间;

    递推 O(n):状态dp[1]=1,dp[2]=2,转移方程dp[i] = dp[i - 1] + dp[i - 2]

    120. Triangle

    Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

    For example, given the following triangle

    [
         [2],
        [3,4],
       [6,5,7],
      [4,1,8,3]
    ]
    class Solution:
        def minimumTotal(self, triangle: List[List[int]]) -> int:
            t = triangle
            if t == '':return 0
            self.dp={}
            return self._dfs(t,0,0)
    
                        
        def _dfs(self,_t,x,y):
            if x >= len(_t):return 0
            if (x,y) not in self.dp:
                mini = min(self._dfs(_t,x+1,y),self._dfs(_t,x+1,y+1))
                self.dp[(x,y)] = _t[x][y] + mini
            return self.dp[(x,y)]
    递归
    class Solution:
        def minimumTotal(self, triangle: List[List[int]]) -> int:
            t = triangle
            if not t: return 0
            
            res=t[-1]
            
            for i in range(len(t)-2,-1,-1):  
                for j in range(len(t[i])):  
                        res[j]=min(res[j],res[j+1])+t[i][j]
                        
            return res[0]
    递推DP

    个人理解:

    递归:从上往下,以元组的形式记录路径字典下标,判断(x+1,y)与(x+1,y+1)之间较小者,带到下一层

    递推:从下往上推断,定义DP[i,j]二维数组,起始值为最后一行,i范围为倒数第二行开始到0 range(len(t)-2,-1,-1),j范围为最后一行,转移方程res[j]=min(res[j],res[j+1])+t[i][j],选择最后一行较小值加上倒数第二行本身
     
     
     
    152. 乘积最大子序列

    Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.

    Example 1:

    Input: [2,3,-2,4]
    Output: 6
    Explanation: [2,3] has the largest product 6.
    

    Example 2:

    Input: [-2,0,-1]
    Output: 0
    Explanation: The result cannot be 2, because [-2,-1] is not a subarray.
     
    class Solution:
        def maxProduct(self, nums: List[int]) -> int:
            if nums == '':return 0
            dp = [[0 for _ in range(2)] for _ in range(2)]
            dp[0][0],dp[0][1],res = nums[0], nums[0],nums[0]
            
            for i in range(1,len(nums)):
                x,y = i%2, (i-1)%2
                dp[x][0] = max(dp[y][0]*nums[i],dp[y][1]*nums[i],nums[i])
                dp[x][1] = min(dp[y][0]*nums[i],dp[y][1]*nums[i],nums[i])
                res = max(res,dp[x][0])
            return res
    递推DP

    个人理解:

    递推:定义状态DP 2X2 二维数组来记录乘或者不乘的结果,初始值都为第一个值,dp[x]记录当前位置,dp[y]为前一个位置,dp[x][0]记录最大值,dp[x][1]记录最小值,0,1 1,0循环使用x,y = i%2, (i-1)%2

    转移方程

    dp[x][0] = max(dp[y][0]*nums[i],dp[y][1]*nums[i],nums[i])
    dp[x][1] = min(dp[y][0]*nums[i],dp[y][1]*nums[i],nums[i])

    if a[i]>0 : dp[i][0] = dp[i-1][0]*a[i]  else : dp[i][0] = dp[i-1][1]*a[i] 
    if a[i]>0 : dp[i][1] = dp[i-1][1]*a[i]  else : dp[i][1] = dp[i-1][0]*a[i] 
     
     
     
    300. 最长上升序列

    Given an unsorted array of integers, find the length of longest increasing subsequence.

    Example:

    Input: [10,9,2,5,3,7,101,18]
    Output: 4 
    Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.
     
    class Solution:
        def lengthOfLIS(self, nums: List[int]) -> int:
            if len(nums) == 0: return 0
            dp = len(nums) * [1]
            res=1
            for i in range(len(nums)):
                for j in range(0,i):
                    if nums[j] < nums[i]:
                        dp[i] =max(dp[i],dp[j]+1)
                res = max(res,dp[i])
            return res
    递推DP
    class Solution:
        def lengthOfLIS(self, nums: List[int]) -> int:
            if len(nums) == 0: return 0
            dp = len(nums) * [0]
            size = 0
            for k in nums:
                i,j = 0,size
                while i!=j:
                    m = (i+j)//2
                    if dp[m] < k:
                        i = m+1
                    else:
                        j = m
                dp[i] = k
                size = max(i+1,size)
            return size
    二分查找新值替换插入

    个人理解:

    暴力法复杂度为n方:递归往下查找,记录取值和不取值的情况,再往下深入,当位置为长度时终止,最后返回取值和不取值中的最大值;

    递推复杂度时间n方、空间为n:dp状态定义开一个数组记录相加次数,转移方程为dp[i] =max(dp[i],dp[j]+1),当原数组当前值比前值大时,在dp中比较当前值的dp数和前值dp数+1哪个大,一层循环后记录本层结果较大值res = max(res,dp[i]),意思是在这之前的有比当前值小的情况dp+1,而比较max可以规避比当前值小但比再前值大的情况;

    二分法时间(nlogn),空间为n:开dp空间,遍历数组,当中间数dp[m]小于当前值时取右边i=m+1,否则取左边j=m,意思是假如当前值为更小值,替换掉该位置的dp值,假如当前值为大值,移动到i位,插入新值,插入值越小后续插入值机会越多,size控制在size = max(i+1,size);

    322.零钱兑换

    You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

    Example 1:

    Input: coins = [1, 2, 5], amount = 11
    Output: 3 
    Explanation: 11 = 5 + 5 + 1

    Example 2:

    Input: coins = [2], amount = 3
    Output: -1

    class Solution:
        def coinChange(self, coins: List[int], amount: int) -> int:
            if amount < 1 :return 0
            k=[0]*amount
            return self._dp(coins,amount,k)
        
        def _dp(self,coins,rem,count):
            if rem<0:return -1
            if rem == 0 : return 0
            if count[rem-1]!=0:return count[rem-1]
            mini = 100
            for coin in coins:
                res = self._dp(coins,rem-coin,count)
                if (res>=0 and res<mini):
                    mini = 1+res
            count[rem-1] = -1 if mini == 100 else mini
            return count[rem-1]
    递归+回溯
    class Solution:
        def coinChange(self, coins: List[int], amount: int) -> int:
            dp = [float('inf')] * (amount + 1)
            dp[0] = 0
            
            for coin in coins:
                for x in range(coin, amount + 1):
                    dp[x] = min(dp[x], dp[x - coin] + 1)
            return dp[amount] if dp[amount] != float('inf') else -1 
    递推DP

    个人理解:

    首先想到暴力法,枚举各个硬币所能兑换的钱数以及各硬币结果合并,所兑换的次数最小者为答案;

    DFS找下一层,将需要求解的值x-coin和count记录数带到下层,返回最小的次数,当rem为0时返回0,count[rem-1]不为0则返回

    其次是动态规划,先DP状态定义,新开一个dp组默认值为inf来表示次数,转移方程为DP[x]=min(DP[x],DP[x-coin[j]]+1)

    当dp组内数字为改变时说明amount无法由coins组成,返回-1,否则返回最后一个dp值,每一个dp值为上一个数兑换硬币后计算

  • 相关阅读:
    短信平台接口调用方法参考
    C#部分类与部分方法
    Oracle表字段类型更改的一个经验
    ueditor的上传文件漏洞(c#)
    判断一个文件是否是指定后缀名的文件
    利用FluorineFx的ByteArray上传图片
    FluorineFx 播放FLV 时堆棧溢出解决 FluorineFx NetStream.play 并发时,无法全部连接成功的解决办法
    Flex数据交互之Remoting[转]
    fluorinefx使用手册
    SharedObject使用:在FluorineFx.net与Flex中使用共享对象维护在线用户列表实例【转】
  • 原文地址:https://www.cnblogs.com/ybxw/p/13458270.html
Copyright © 2011-2022 走看看