动态规划,递增序列300,674,322零钱兑换,72word距离

674.

动态规划,递增序列300,674,322零钱兑换,72word距离

class Solution:
    def findLengthOfLCIS(self, nums: List[int]) -> int:
        max_l = 1
        l = 1
        for i in range(1,len(nums)):
            if nums[i] <=nums[i-1]:
                l = 1
            else:
                l += 1
                max_l = max(max_l,l)
        return max_l

300.

动态规划,递增序列300,674,322零钱兑换,72word距离

错误代码:

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        n = len(nums)
        if n <= 1:
            return n
        DP = [1]*n
        for i in range(0,n-1):
            for j in range(0,i):
                if(nums[i]>nums[j]):
                    DP[i] = max(DP[i],DP[j]+1)
        return max(DP[:])

存在的问题:DP[i] 应该需要从1循环到n-1。DP[0] = 1

正确代码:

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        n = len(nums)
        if n <= 1:
            return n
        DP = [1]*n
        for i in range(1,n):
            for j in range(0,i):
                if(nums[i]>nums[j]):
                    DP[i] = max(DP[i],DP[j]+1)
        return max(DP[:])

特殊解法:查找

不断地去维护更新一个lis,这个list的长度就是最长递增子序列、

动态规划,递增序列300,674,322零钱兑换,72word距离

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        n = len(nums)
        if n <= 1:
            return n
        lis = []
        for i in range(len(nums)):
            if not lis:
                lis.append(nums[i])
            elif nums[i]>lis[-1]:
                lis.append(nums[i])
            elif len(lis) ==1:
                    lis[0] = nums[i]
            else:
                for j in range(len(lis)):
                    if nums[i]<= lis[j] :
                        lis[j] = nums[i]
                        break
        return len(lis)

注意这个地方nums[i]<=lis[j] 的替换

这个地方我们替换的是存在于序列中大于等于nums[i]的最小数

322.零钱兑换系列

有问题的代码:暂时还没修复。DFS暴力破解

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        self.coins = sorted(coins)
        self.min_num = -1
        n = len(coins)-1
        self.dfs(amount,n,0)
        return int(self.min_num)
        
    def dfs(self,amount,n,ans):
        if n<0:
            return False
        if amount % self.coins[n] == 0:
            ans += amount / self.coins[n]
            self.min_num=ans
            return True
        if amount < self.coins[0] :
            return False
        num = amount // self.coins[n]
        for num_coin in range(num,-1,-1):
            total = num_coin* self.coins[n]
            if(self.dfs(amount-total,n-1,ans+num_coin)):
                break
        return True

用动态规划来做:

有问题的代码:

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [0]+[10001]*amount
        dp[0] = 0 
        for coin in coins:
            for i in range(amount+1):
                dp[i] = min(dp[i],dp[i-coin]+1)
        if dp[-1] == 10001:
            return -1
        else:
            return dp[-1]

问题:dp[i-coin]:i-coin这里有可能是硬币叠加达不到的数量

修复问题:

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [0]+[10001]*amount
        dp[0] = 0 
        for coin in coins:
            for i in range(coin,amount+1):
                dp[i] = min(dp[i],dp[i-coin]+1)
        if dp[-1] == 10001:
            return -1
        else:
            return dp[-1]
  • 时间复杂度:O(n * amount)
  • 空间复杂度:O(amount)

学习简化if else的一种写法: 

注意

 return dp[-1] == 10001 ? -1:dp[-1] 

只能在C++里面用,python没有

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [0]+[10001]*amount
        dp[0] = 0 
        for coin in coins:
            for i in range(coin,amount+1):
                dp[i] = min(dp[i],dp[i-coin]+1)
        return dp[-1] if dp[-1] != 10001 else -1
        

可以这么简化

72:

动态规划,递增序列300,674,322零钱兑换,72word距离
错误代码:

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        n1 = len(word1)
        n2 = len(word2)
        DP = [[0]*(n1+1)for _ in range(n2+1)]
        for i in range(n1+1):
            DP[0][i] = i
        for j in range(n2+1):
            DP[j][0] = j
        for i in range(1,n1+1):
            for j in range(1,n2+1):
                if word1[i-1] == word2[j-1]:
                    DP[i][j] = DP[i-1][j-1]
                else:
                    DP[i][j] = min(DP[i-1][j-1],DP[i-1][j],DP[i][j-1])+1
        return DP[-1][-1]

            

错误原因:DP[i][j]  是把word1[i-1] 变成word[j-1] 的字符串的最小操作次数。需要搞清楚维度

import numpy as np
DP = [[0] * (5) for _ in range(6)]
print(np.array(DP).shape)
#(6, 5)

思路理解强调:

对“dp[i-1][j-1] 表示替换操作,dp[i-1][j] 表示删除操作,dp[i][j-1] 表示插入操作。”的补充理解:

以 word1 为 "horse",word2 为 "ros",且 dp[5][3] 为例,即要将 word1的前 5 个字符转换为 word2的前 3 个字符,也就是将 horse 转换为 ros,因此有:

(1)替换操作: dp[i-1][j-1],即先将 word1 的前 4 个字符 hors 转换为 word2 的前 2 个字符 ro,然后将第五个字符 word1[4](因为下标基数以 0 开始) 由 e 替换为 s(即替换为 word2 的第三个字符,word2[2])

(2)插入操作: dp[i][j-1],即先将 word1 的前 5 个字符 horse 转换为 word2 的前 2 个字符 ro,然后在末尾补充一个 s

(3)删除操作: dp[i-1][j],即先将 word1 的前 4 个字符 hors 转换为 word2 的前 3 个字符 ros,然后删除 word1 的第 5 个字符

正确代码:

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        n1 = len(word1)
        n2 = len(word2)
        DP = [[0]*(n2+1)for _ in range(n1+1)]
        for i in range(n1+1):
            DP[i][0] = i
        for j in range(n2+1):
            DP[0][j] = j
        for i in range(1,n1+1):
            for j in range(1,n2+1):
                if word1[i-1] == word2[j-1]:
                    DP[i][j] = DP[i-1][j-1]
                else:
                    DP[i][j] = min(DP[i-1][j-1],DP[i-1][j],DP[i][j-1])+1
        return DP[-1][-1]

            

时间复杂度:O((n1+1)*(n1+2))

空间复杂度:O

上一篇:一起“干完”这份300页1000道面试题,进阶学习


下一篇:win10系统下安装Ubuntu18.04双系统