LeetCode刷题:动态规划专题

目录

 

5. Longest Palindromic Substring

10. Regular Expression Matching

53. Maximum Subarray

62. Unique Paths

63. Unique Paths II

70. Climbing Stairs

72. Edit Distance

 78. Subsets

 115. Distinct Subsequences

 120. Triangle

 139. Word Break

140. Word Break II

198. House Robber

213. House Robber II

 221. Maximal Square

279. Perfect Squares

322. Coin Change

337. House Robber III

 338. Counting Bits

343. Integer Break

377. Combination Sum IV

474. Ones and Zeroes

494. Target Sum

523. Continuous Subarray Sum

576. Out of Boundary Paths

647. Palindromic Substrings

最大和子矩阵


 

5. Longest Palindromic Substring

题目链接:https://leetcode.com/problems/longest-palindromic-substring/

题目思路:

有两种方法。

1.dp的思路,if s[i]=s[j], dp[i][j]=dp[i+1][j-1],max_len=max(max_len,j-i+1).

2.对0-len(s)-1的每个位置,分别按照奇偶的方式遍历,如果左右两端的字符相同,则继续向外扩张。

class Solution(object):
    def longestPalindrome1(self, s):
        res = ""
        for i in xrange(len(s)):
            # odd case, like "aba"
            tmp = self.helper(s, i, i)
            if len(tmp) > len(res):
                res = tmp
            # even case, like "abba"
            tmp = self.helper(s, i, i+1)
            if len(tmp) > len(res):
                res = tmp
        return res
 
    def longestPalindrome(self, s):
        n=len(s)
        dp=[[0]*n for _ in range(n)]
        max_len=0
        ans=''

        for i in range(n):
            dp[i][i]=1
            max_len=1
            ans=s[i]
        res=0
        for i in range(n-1):
            if s[i]==s[i+1]:
                dp[i][i+1]=1
                res=2
                ans=s[i:i+2]
                max_len+2
        for j in range(n):
            for i in range(j-1):
                if dp[i+1][j-1] and s[i]==s[j]:
                    dp[i][j]=True
                    if j-i+1>max_len:
                        max_len=j-i+1
                        ans=s[i:j+1]
        return ans
            
        
        
    def helper(self, s, l, r):
        while l >= 0 and r < len(s) and s[l] == s[r]:
            l -= 1; r += 1
        return s[l+1:r]

 

10. Regular Expression Matching

题目链接:https://leetcode.com/problems/regular-expression-matching/

这个问题主要是正则规则的理解,多submit几次就懂了【滑稽】。

需要关注的判断条件是s[i],p[j]是否相等,p[j+1]是否为‘*’,p[j]是否为'.'。

只有两个字符串都遍历完了的情况,这时可以返回true。

class Solution(object):
    def isMatch(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: bool
        """
        l1,l2=len(s),len(p)
        def match(i,j):
            if i==l1 and j==l2:
                return True
            elif i<l1 and j==l2:
                return False
            elif i==l1 and j<l2:
                if j+1==l2:
                    return False
                elif p[j+1]=='*':
                    return match(i,j+2)
                else:
                    return False
            if j+1==l2:
                if p[j]=='.' or s[i]==p[j]:
                    return match(i+1,j+1)
                else:
                    return False
            if s[i]!=p[j]:
                if p[j+1]=='*':
                    if p[j]=='.':
                        return match(i,j+2) or match(i+1,j)
                    else:
                        return match(i,j+2)
                else:
                    if p[j]=='.':
                        return match(i+1,1+j)
                    else:
                        return False
            else:
                if p[j+1]=='*':
                    return match(i+1,j) or match(i,j+2)
                else:
                    return match(i+1,1+j)
        return match(0,0)

53. Maximum Subarray

https://leetcode.com/problems/maximum-subarray/

class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        res=nums[0]
        dp=[0]*len(nums)
        dp[0]=nums[0]
        for i in range(1,len(nums)):
            dp[i]=max(dp[i-1]+nums[i],nums[i])
            res=max(res,dp[i])
        print(dp)
        return res

 

62. Unique Paths

题目链接:https://leetcode.com/problems/unique-paths/

class Solution(object):
    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        res=[[0]*(1+n) for _ in range(1+m)]
        res[1][1]=1
        # for i in range(1,m):
        #     res[i][0]=res[i-1][0]+1
        # for i in range(1,n):
        #     res[0][i]=res[0][i-1]+1
        for i in range(1,m+1):
            for j in range(1,n+1):
                res[i][j]+=res[i][j-1]
                res[i][j]+=res[i-1][j]
        print(res)
        return res[m][n]

63. Unique Paths II

题目链接:https://leetcode.com/problems/unique-paths-ii/

class Solution(object):
    def uniquePathsWithObstacles(self, o):
        """
        :type obstacleGrid: List[List[int]]
        :rtype: int
        """
        if o==[[1]]:
            return 0
        m,n=len(o),len(o[0])
        res=[[0]*(n+1) for _ in range(m+1)]
        res[1][1]=1
        for i in range(1,1+m):
            for j in range(1,1+n):
                if o[i-1][j-1]:
                    pass
                else:
                    if o[i-1][j-2] != 1:
                        res[i][j]+=res[i][j-1]
                    if o[i-2][j-1] != 1:
                        res[i][j]+=res[i-1][j]
        # print(res)
        return res[m][n]

70. Climbing Stairs

题目链接:

设d(x)为金额为x时爬楼梯的方式数目

  1. 初始条件:d(0)=1,x<0时,d(x)=0。或者是d(1)=1,d(2)=2,x<1时,d(x)=0
  2. 递归方程:d(x)=d(x-1)+d(x-2)
  3. 优化方式:将已经计算好的d(x)存起来,防止多次计算同一个值
class Solution(object):
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        a={}
        def d(x):
            if a.__contains__(x):
                return a[x]
            res=0
            if x==0:
                res= 1
            elif x<0:
                return 0
            else:
                res= d(x-1)+d(x-2)
            a[x]=res
            return res
        return d(n)

 

72. Edit Distance

题目链接:https://leetcode.com/problems/edit-distance/

关键是递归关系,因为置换、删除和插入都需要一次,所以递归方程如下:

if word1[i-1]==word2[j-1]:
    dp[i][j]=dp[i-1][j-1]
else:
    dp[i][j]=1+min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])
class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        l1,l2=len(word1),len(word2)
        dp=[[0]*(l2+1) for _ in range(l1+1)]
        print(dp)
        for j in range(1,l2+1):  
            dp[0][j]=dp[0][j-1]+1
        for i in range(1,l1+1):
            dp[i][0]=dp[i-1][0]+1

        print(dp)
        for i in range(1,l1+1):
            for j in range(1,l2+1):                 
                if word1[i-1]==word2[j-1]:
                    dp[i][j]=dp[i-1][j-1]
                else:
                    dp[i][j]=1+min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])
                # print(i,j,dp[i][j])
        return dp[l1][l2]

 78. Subsets

题目链接:https://leetcode.com/problems/subsets/

思路,每次遍历所有元素,对res内里的所有子集都加一下。递归方程是dp[i+1]=[[nums[i]]+j for j in dp[i]]

def subsets(nums):
    res = [[]]
    for n in nums:
        for i in range(len(res)):
            res.append(res[i] + [n])
            # print(res)
    print(res)

 

 115. Distinct Subsequences

题目链接:https://leetcode.com/problems/distinct-subsequences/

题目思路:相当于0/1背包问题,dp(a,b)表示在a里找到b的次数。对a里的元素遍历,如果和b[0]相同,则去除第一个元素,求次数之和。

class Solution(object):
    def numDistinct(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: int
        """
        d={}
        res=0
        def dp(a,b):
            if len(a)<len(b):
                return 0
            elif len(b)==1:
                return a.count(b) 
            elif d.__contains__((a,b)):
                return d[(a,b)]
            else:
                res=0
                for i in range(len(a)):
                    if a[i]!=b[0]:
                        pass
                    else:
                        res+=dp(a[i+1:],b[1:])#+dp(a[i+1:],b)
                d[(a,b)]=res
                return res
        return dp(s,t)
                    
                    # bbit,bit
                

 

 120. Triangle

题目链接:https://leetcode.com/problems/triangle/

class Solution(object):
    def minimumTotal(self, t):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        l=len(t)
        res=[[0]*len(t[-1]) for _ in range(l)]
        res[-1]=t[-1]
        for i in range(l-2,-1,-1):
            x=len(t[i])
            for j in range(x):
                res[i][j]=min(res[i+1][j],res[i+1][j+1])+t[i][j]
        # print(res)
        return res[0][0]

 139. Word Break

题目链接:https://leetcode.com/problems/word-break/

class Solution(object):
    def wordBreak(self, s, w):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        res=False
        d={}
        if not s:
            return False
        def dp(t):
            if not t:
                return True
            elif d.__contains__(t):
                return d[t]
            else:
                res=False
                for word in w:
                    if t.startswith(word):
                        res = res or dp(t[len(word):])
                d[t]=res
                return res
        return dp(s)
        

140. Word Break II

题目链接:https://leetcode.com/problems/word-break-ii/

题目思路:每次对于当前字符串,搜索元素集合,对于开头是i的字符串,搜索i后面的字符串的组合结果,再拼接在一起。

class Solution(object):
    def wordBreak(self, s, w):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        res=False
        d={}
        if not s:
            return []
        def dp(t):
            if d.__contains__(t):
                return d[t]
            else:
                res=[]
                for word in w:
                    if t.startswith(word):
                        if t==word:
                            res+=[word]
                        else:
                            x=dp(t[len(word):])
                            if x:
                                for i in x:
                                    res.append(word+' '+i)
                d[t]=res
                return res
        x=dp(s)
        # print(d)
        return x
        

 

198. House Robber

题目链接:https://leetcode.com/problems/house-robber/

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        
        n=len(nums)
        if n==0:
            return 0
        # elif n==1:
        #     return 1
        d={}
        def dp(i):
            if i>=n:
                return 0
            elif d.__contains__(i):
                return d[i]
            else:
                res=max(nums[i]+dp(i+2), dp(i+1))
                d[i]=res
                return max(nums[i]+dp(i+2), dp(i+1))
        return dp(0)

213. House Robber II

题目链接:https://leetcode.com/problems/house-robber-ii/

这里的思路是,从0开始偷,最后一个不能偷,倒数第二个肯定可以偷;如果从1开始偷,那就随意了。所以应该求0-n-2和1-n-1这两段之间偷的最大值。

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        
        n=len(nums)
        if n==0:
            return 0
        elif n==1:
            return nums[0]
        elif n==2:
            return max(nums)
        d={}
        def dp(i,l):
            if i>=l:
                return 0
            elif d.__contains__(i):
                return d[i]
            else:
                res=max(nums[i]+dp(i+2,l), dp(i+1,l))
                d[i]=res
                return res
        x=dp(1,n)
        d={}
        y=dp(0,n-1)
        return max(x,y)

 221. Maximal Square

题目链接:https://leetcode.com/problems/maximal-square/

这里采用了最直观的方法,类似于求直方图的最大面积。

class Solution(object):
    def maximalSquare(self, matrix):
        """
        :type matrix: List[List[str]]
        :rtype: int
        """
        max_len=0
        if not matrix:
            return 0
        m,n=len(matrix),len(matrix[0])
        if not n:
            return 0
        his=[int(i) for i in matrix[-1]]
        if 1 in his:
            max_len=1
        for i in range(m-2,-1,-1):
            for j in range(n):
                if '1' in matrix[i]:
                    max_len=max(max_len,1)
                his[j]+=int(matrix[i][j])
                his[j]*=int(matrix[i][j])
            # print(his)
            for j in range(n):
                if his[j]<=1:
                    continue
                min_len=1
                for k in range(j+1,n):
                    if his[k]<=1:
                        break
                    else:
                        min_len=min(his[j:k+1])
                        # print(min_len)
                        if k-j+1>min_len:
                            min_len=k-j
                            break
                        min_len=min(min_len,k-j+1)
                max_len=max(max_len,min_len)
        return max_len*max_len
            
        

279. Perfect Squares

题目链接:https://leetcode.com/problems/perfect-squares/

题目思路:如果i本身就是平方数,则返回1;否则,从最大int(sqrt(i))开始遍历,寻找最短的步数。

import math
class Solution(object):
    def numSquares(self, n):
        """
        :type n: int
        :rtype: int
        """
        d={8:2,4:1,9:1,1:1,2:2,3:3,16:1}
        def dfs(i):
            if d.__contains__(i):
                return d[i]
            a=math.sqrt(i)
            if int(a)==a:
                d[i]=1
                return 1
            res=i
            for j in range(int(a),1,-1):
                t=dfs(i-j*j)
                res=min(res,t+1)
            d[i]=res
            return res
        return dfs(n)

 

322. Coin Change

题目链接:https://leetcode.com/problems/coin-change/

和第70题思路一样。

class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        
        t={}
        def g(a):
            if t.__contains__(a):
                return t[a]
            elif a==0:
                return 0
            elif a<0:
                return -1
            else:
                c=[g(a-i) for i in coins if g(a-i)>=0]
                if c==[]:
                    res = -1
                else:
                    res=min(c)+1

            t[a]=res
            return res
        return g(amount)

337. House Robber III

思路,dfs遍历所有节点,每个节点返回两个值(a,b):a是经过当前节点往下的最大值,b是不经过当前节点往下的最大值路径。则每个节点的值a等于当前的节点值+左右子节点b之和,每个节点的值b等于左右子节点的max(a,b)之和。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def rob(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        d={}
        def dfs(node):
            if not node:
                return 0, 0
            x,y=dfs(node.left),dfs(node.right)
            # print(node.val,node.val+x[1]+y[1],x[0]+y[0])
            return node.val+x[1]+y[1],max(x)+max(y)
            
        return max(dfs(root))
        

 338. Counting Bits

题目链接:https://leetcode.com/problems/counting-bits/

思路是每个数是前一个数+1的结果,看看发生了几次进位。

递归关系如下:如果0次进位,那么说明最后一位是0,1的个数直接+1;如果1次进位,那么1的个数不变;如果是k次进位,那么减少了k个1,增加了一个1,总共减少了k-1个1。

class Solution(object):
    def countBits(self, num):
        """
        :type num: int
        :rtype: List[int]
        """
        def get_flag(a,b):
            cnt=0
            while b!=0:
                sum=a^b
                flag=(a&b)<<1
                a=sum
                b=flag
                cnt+=1
            return cnt-1
        if num==0:
            return [0]
        res=[0,1]
        for i in range(1,num):
            flag = get_flag(i,1)
            if flag==0:
                res.append(res[-1]+1)
            elif flag==1:
                res.append(res[-1])
            else:
                res.append(res[-1]-flag+1)
        return res

 

343. Integer Break

题目链接:https://leetcode.com/problems/integer-break/

class Solution(object):
    def integerBreak(self, n):
        """
        :type n: int
        :rtype: int
        """
        d={2:1,3:2}
        def dfs(i):
            if d.__contains__(i):
                return d[i]
            res=0
            for j in range(1,i):
                res=max(res,j*dfs(i-j),j*(i-j))
            d[i]=res
            return res

        return dfs(n)

 

377. Combination Sum IV

题目链接:https://leetcode.com/problems/combination-sum-iv/

class Solution(object):
    def combinationSum4(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        d={}
        
        def dp(x):
            if x==0:
                return 1
            elif d.__contains__(x):
                return d[x]
            else:
                res=0
                for i in nums:
                    if x>=i:
                        res+=dp(x-i)
                d[x]=res
            return res

        return dp(target)

474. Ones and Zeroes

题目链接:https://leetcode.com/problems/ones-and-zeroes/

典型0-1背包问题,没啥好说的,注意迭代公式即可。

class Solution(object):
    def findMaxForm(self, strs, m, n):
        """
        :type strs: List[str]
        :type m: int
        :type n: int
        :rtype: int
        """
        # strs=list(set(strs))
        d={i:[strs[i].count('0'),strs[i].count('1')] for i in range(len(strs))}
        # print(d)

        a=[[[0 for _ in range(len(strs)+1)] for _ in range(n+1)] for _ in range(m+1)]
        for i in range(1,len(strs)+1):
            for x in range(1+m):
                for y in range(1+n):
                    if x-d[i-1][0]<0 or y-d[i-1][1]<0:
                        a[x][y][i]=a[x][y][i-1]
                    else:
                        a[x][y][i]=max(a[x-d[i-1][0]][y-d[i-1][1]][i-1]+1,a[x][y][i-1])
                    # print(x,y,i,a[x][y][i])
        return a[m][n][-1]
        
        

494. Target Sum

题目链接:https://leetcode.com/problems/target-sum/

class Solution(object):
    def findTargetSumWays(self, nums, S):
        """
        :type nums: List[int]
        :type S: int
        :rtype: int
        """
        n=len(nums)
        d={}
        def dfs(i,su):
            if i==n:
                if su==0:
                    return 1
                else:
                    return 0
            elif d.__contains__((i,su)):
                return d[(i,su)]
            else:
                res=dfs(i+1,su-nums[i])+dfs(i+1,su+nums[i])
                d[(i,su)]=res
                return res
        return dfs(0,S)

 

523. Continuous Subarray Sum

题目链接:https://leetcode.com/problems/continuous-subarray-sum/

如果sum(a[i:j])%k==0,sum(a[:i])%k==sum(a[:j])%k,在mod k情况下,sum值是相同的。

class Solution():
    def checkSubarraySum(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: bool
        """
        dic = {0:-1}
        summ = 0
        for i, n in enumerate(nums):
            if k != 0:
                summ = (summ + n) % k
            else:
                summ += n
            if summ not in dic:
                dic[summ] = i
            else:
                if i - dic[summ] >= 2:
                    return True
        return False

576. Out of Boundary Paths

题目链接:https://leetcode.com/problems/out-of-boundary-paths/

class Solution(object):
    def findPaths(self, m, n, N, i, j):
        """
        :type m: int
        :type n: int
        :type N: int
        :type i: int
        :type j: int
        :rtype: int
        """
        Max=1e9+7
        def out_of_box(x,y):
            if 0<=x<m and 0<=y<n:
                return False
            return True
        d={}
        def dfs(i,j,times):
            s=[(1,0),(-1,0),(0,1),(0,-1)]
            
            if out_of_box(i,j):
                if times==0:
                    return 1
                return -1
            elif times==0:
                return -1
            elif d.__contains__((i,j,times)):
                return d[(i,j,times)]
            res=0
            for step in s:
                x,y=i+step[0],j+step[1]
                t=dfs(x,y,times-1)
                if t!=-1:
                    res+=t
            if res==0:
                d[(i,j,times)]= -1
            else:
                d[(i,j,times)]=int(res%Max)
            return d[(i,j,times)]
        res=0
        for t in range(1,N+1):
            x=dfs(i,j,t)
            if x>0:
                res+=x
        return int(res%Max)
                    

 

647. Palindromic Substrings

题目链接:https://leetcode.com/problems/palindromic-substrings/

class Solution(object):
    def countSubstrings(self, s):
        res = 0
        for i in xrange(len(s)):
            # odd case, like "aba"
            tmp = self.helper(s, i, i)
            res+=tmp
            # even case, like "abba"
            tmp = self.helper(s, i, i+1)
            res+=tmp
        return res
            
        
    def helper(self, s, l, r):
        res=0
        while l >= 0 and r < len(s) and s[l] == s[r]:
            res+=1
            l -= 1; r += 1
        return res

最大和子矩阵

问题描述:求一个二维矩阵里所有元素之和最大的子矩阵。

例如,以下矩阵中最大和的子矩阵是红框内的。

思路:可以每次求出第i到j行的每列元素之和,这样就可以转化成最大连续子数组之和的问题。时间复杂度为O(n^2)

def max_sum_matrix():
    a=[[1,0,-7,6],[1,-4,3,0],[-1,2,-7,9],[2,0,4,-3]]
    n = len(a)
    tmp=[[0]*n for _ in range(n)]
    tmp[0] = a[0]
    for i in range(1, n):
        for j in range(n):
            tmp[i][j] = tmp[i-1][j] + a[i][j]
    s=[0]*n
    res=-1e9
    for i in range(n):
        for j in range(i+1, n):
            cur = -1e9

            for k in range(n):
                if i == 0:
                    s[k] = tmp[j][k]
                else:
                    s[k] = tmp[j][k] - tmp[i-1][k]
            for k in range(n):
                cur = max(s[k]+cur, s[k])
                res=max(res, cur)
            print(s, cur, res)

    print(res)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值