Leetcode题解-动态规划部分

参考:leetcode 题解

Largest rectangle in Histogram

对于每一根bar,记录包含该bar的矩形区域里面该bar是最小的面积。

class Solution:
    def largestRectangleArea(self, heights):
        """
        :type heights: List[int]
        :rtype: int
        """

        heights.append(0)
        stack=[-1]
        i=0
        res=0
        while i<=len(heights)-1:
            if heights[i]<heights[stack[-1]]:
                t=stack.pop()
                hi=heights[t]
                wi=i-stack[-1]-1
                res=max(res,hi*wi)
            else:
                stack.append(i)
                i+=1

        return res

Maximal rectangle

class Solution:
    def maximalRectangle(self, matrix):
        """
        :type matrix: List[List[str]]
        :rtype: int
        """
        if not matrix:
            return 0
        if not matrix[0]:
            return 0

        m=len(matrix)
        n=len(matrix[0])
        f=[[0]*n for _ in range(m)] #以每一行为底的直方图的高度
        for i in range(m): 
            for j in range(n):
                if i==0:
                    f[i][j]=int(matrix[i][j])
                    continue

                if matrix[i][j]=="0":
                    f[i][j]=0
                else:
                    f[i][j]=f[i-1][j]+1

        res=0
        for i in range(m):
            res=max(self.largestArea(f[i]),res)
        return res

    def largestArea(self,heights):
        stack=[-1]
        heights.append(0)
        i=0
        res=0
        while i<=len(heights)-1:
            if heights[i]<heights[stack[-1]]:
                t=stack.pop()
                hi=heights[t]
                wi=i-stack[-1]-1
                res=max(res,hi*wi)
            else:
                stack.append(i)
                i+=1

        return res

Unique Binary Search Trees

https://leetcode.com/problems/unique-binary-search-trees/description/
卡特兰数

f [ 0 ] = 1 , f [ 1 ] = 1 f [ 2 ] = f [ 0 ] f [ 1 ] + f [ 1 ] f [ 0 ] = 2 f [ 3 ] = f [ 0 ] f [ 2 ] + f [ 1 ] f [ 1 ] + f [ 2 ] f [ 0 ] = 5 f [ n ] = f [ 0 ] f [ n 1 ] + f [ 1 ] f [ n 2 ] + + f [ n 1 ] [ 0 ] f [ n ] = 1 n + 1 C 2 n n = ( 2 n ) ! ( n + 1 ) ! n !

class Solution:
    def numTrees(self, n):
        """
        :type n: int
        :rtype: int
        """

        f=[0]*(n+1)
        f[0]=1

        for i in range(1,n+1): 
            for root in range(1,i+1): 
                f[i]=f[i]+f[root-1]*f[i-root]

        return f[-1]

Unique Binary Search Trees II

class Solution:
    def generateTrees(self, n):
        """
        :type n: int
        :rtype: List[TreeNode]
        """
        if n==0:
            return []
        res=self.helper(1,n)
        return res


    def helper(self,start,end):
        if start>end:
            return [None]
        res=[]
        for i in range(start,end+1):
            for l in self.helper(start,i-1):
                for r in self.helper(i+1,end):
                    tmp=TreeNode(i)
                    tmp.left=l
                    tmp.right=r
                    res.append(tmp)

        return res

Triangle

class Solution:
    def minimumTotal(self, triangle):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        #bottom up
        height=len(triangle)
        f=[[float('inf')]*n for n in range(1,height+1)]

        for layer in range(height-1,-1,-1):
            for k in range(layer+1):
                if layer==height-1:
                    f[layer][k]=triangle[layer][k]
                    continue
                f[layer][k]=min(f[layer+1][k],f[layer+1][k+1])+triangle[layer][k]

        return min(f[0])

Range sum query

class Solution:
    def minimumTotal(self, triangle):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        height=len(triangle)
        f=[[float('inf')]*n for n in range(1,height+1)]

        for layer in range(height-1,-1,-1):
            for k in range(layer+1):
                if layer==height-1:
                    f[layer][k]=triangle[layer][k]
                    continue
                f[layer][k]=min(f[layer+1][k],f[layer+1][k+1])+triangle[layer][k]

        return min(f[0])

Best time to buy and sell stock III

class Solution:
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        if not prices:
            return 0
        k=2
        n=len(prices)
        f=[[0]*n for _ in range(k+1)]#在进行k(0,1,...,k)次交易的情况下,第day天能够获得的最大收益

        for t in range(k+1): 
            for day in range(n):
                if day==0:
                    f[t][day]=0
                    continue
                if t==0:
                    f[t][day]=0
                    continue

                f[t][day]=f[t][day-1]#第day天不进行交易

                # time exceeded
                for j in range(0,day): #第day天卖出
                    if j>=1: #第j天买入
                        f[t][day]=max(f[t][day],prices[day]-prices[j]+f[t-1][j-1])
                    else:
                        f[t][day]=max(f[t][day],prices[day]-prices[j])


        return f[-1][-1]

改进:

class Solution:
    def maxProfit(self,  prices):
        """
        :type k: int
        :type prices: List[int]
        :rtype: int
        """
        if not prices:
            return 0
        n=len(prices)
        k=2
        f=[[0]*n for _ in range(k+1)]

        #memory exceeded
        maxProfit=0
        for t in range(1,k+1): 
            minP=prices[0]
            for day in range(1,n):   
                minP=min(minP, prices[day]-f[t-1][day-1])

                f[t][day]=max(f[t][day-1], prices[day]-minP)
                maxProfit=max(maxProfit,f[t][day])

        return maxProfit

Is it Best Solution with O(n), O(1).

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        hold1=-sys.maxsize #max profit if just buy 1st stock
        hold2=-sys.maxsize #max profit if just buy 2nd stock

        sell1=0 # max if just sold 1st stock
        sell2=0 # max if just sold 2nd stock
        for p in prices:
            sell2=max(sell2,hold2+p)
            hold2=max(hold2,sell1-p)
            sell1=max(sell1,hold1+p)
            hold1=max(hold1,-p)

        return max(hold1,hold2,sell1,sell2)

Best time to buy and sell stock IV

这里写代码片

Distinct Subsequence

class Solution(object):
    def numDistinct(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: int
        """
        n=len(s)
        m=len(t)
        f=[[0]*(m+1) for i in range(n+1)] # f[i][j]: s[:i]包含多少个t[:j]
        for j in range(m+1):
            for i in range(j,n+1):
                if i==0 and j==0:
                    f[i][j]=1
                    continue
                if j==0:
                    f[i][j]=1
                    continue
                if i==0:
                    f[i][j]=0
                    continue

                f[i][j]=f[i-1][j]
                if s[i-1]==t[j-1]:
                    f[i][j]=f[i][j]+f[i-1][j-1]
        return f[-1][-1]

Longest Valid Parentheses

My DP, O(n) solution without using stack
My solution uses DP. The main idea is as follows: I construct a array longest[], for any longest[i], it stores the longest length of valid parentheses which is end at i.

And the DP idea is :

If s[i] is ‘(‘, set longest[i] to 0,because any string end with ‘(’ cannot be a valid one.

Else if s[i] is ‘)’

 If s[i-1] is '(', longest[i] = longest[i-2] + 2

 Else if s[i-1] is ')' and s[i-longest[i-1]-1] == '(', longest[i] = longest[i-1] + 2 + longest[i-longest[i-1]-2]

For example, input “()(())”, at i = 5, longest array is [0,2,0,0,2,0], longest[5] = longest[4] + 2 + longest[1] = 6.

class Solution(object):
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s:
            return 0
        n=len(s)

        f=[0]*(n) # f[i]: longest valid parentheses end with s[i]

        res=0
        for i in range(n):
            if s[i]=="(":
                continue #肯定是0
            else: #s[i]==")"
                if i>=1:
                    if s[i-1]=="(": #f[i]=f[i-2]+2
                        f[i]=2
                        if i>=2:
                            f[i]+=f[i-2]
                    elif s[i-1]==")" and i-1-f[i-1]>=0 and s[i-1-f[i-1]]=="(": #  i-1-f[i-1]   i-1-f[i-1]+1   i-1 i
                        f[i]=f[i-1]+2 # f[i]=f[i-1]+2+f[i-2-f[i-1]]
                        if i-f[i-1]-2>=0:
                            f[i]+=f[i-f[i-1]-2]
            res=max(res,f[i])

        return res

word break

class Solution:
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        n=len(s)
        f=[False]*n # f[i]: if s[:i+1] if valid for wordDict
        for i in range(n):
            for w in wordDict:
                if s[i-len(w)+1:i+1]==w and (f[i-len(w)]==True or i-len(w)==-1):
                    f[i]=True
                    break
        return f[-1]

word break II

Python easy-to-understand solution

  • Every time, we check whether s starts with a word. If so, we check whether the substring s[len(word):] starts with a word, etc.
  • resultOfTheRest keeps calling until we hit the last word. If the last word is in the dict, we append it to res. The last word is ‘dog’
    ==> ‘res = [ “dog”]
  • This time, we skip “else,” since we fulfill the condition ” if len(word) == len(s).” We store it in memo: {‘dog’: [‘dog’]}

4.Then we return to “resultOfTheRest = self.helper(s[len(word):], wordDict, memo)”

class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: List[str]
        """
        res=self.helper(s,wordDict,{})
        return res

    def helper(self,s,wordDict,memo):
        if not s:
            return []
        if s in memo:
            return memo[s]

        res=[]
        for word in wordDict:
            if not s.startswith(word):
                continue
            # s.startswith(word)
            if len(s)==len(word): #find the last word
                res.append(word)
            else:
                result=self.helper(s[len(word):],wordDict,memo)
                res+=[word+" "+item for item in result]

        memo[s]=res
        return res

Min cost climbing stairs

class Solution:
    def minCostClimbingStairs(self, cost):
        """
        :type cost: List[int]
        :rtype: int
        """
        if not cost or len(cost)==2:
            return 0
        n=len(cost)
        f=[float('inf')]*(n+1) # need to cross the last step, which is equivalent to reach (n+1)th
        f[0]=0 # since we can start at either 
        f[1]=0

        for i in range(2,n+1):
            f[i]=min(f[i-1]+cost[i-1],f[i-2]+cost[i-2])

        return f[-1]

Ugly number

class Solution(object):
    def nthUglyNumber(self, n):
        """
        :type n: int
        :rtype: int
        """
        uglynum=[1]
        i2,i3,i5=0,0,0
        for i in range(1,n):
            num=min(uglynum[i2]*2,uglynum[i3]*3,uglynum[i5]*5)
            uglynum.append(num)
            if num==uglynum[i2]*2:
                i2+=1
            if num==uglynum[i3]*3:
                i3+=1
            if num==uglynum[i5]*5:
                i5+=1

        return uglynum[-1]

Interleaving String

class Solution(object):
    def isInterleave(self, s1, s2, s3):
        """
        :type s1: str
        :type s2: str
        :type s3: str
        :rtype: bool
        """
        #f[i][j]: s1[:i], s2[:j]能不能拼出 s3[:(i+j)]
        n1=len(s1)
        n2=len(s2)
        if n1+n2!=len(s3):
            return False
        f=[[False]*(n2+1) for _ in range(n1+1)]

        for i in range(n1+1):
            for j in range(n2+1):
                if i==0 and j==0:
                    f[i][j]=True
                    continue
                if i==0:
                    f[i][j]=f[i][j-1] and s3[j-1]==s2[j-1]
                    continue
                if j==0:
                    f[i][j]=f[i-1][j] and s3[i-1]==s1[i-1]
                    continue

                if s3[i+j-1]==s2[j-1]:
                    f[i][j]=f[i][j] or f[i][j-1]
                if s3[i+j-1]==s1[i-1]:
                    f[i][j]=f[i][j] or f[i-1][j]

        return f[-1][-1]

Integer break

class Solution(object):
    def integerBreak(self, n):
        """
        :type n: int
        :rtype: int
        """
        f=[0]*(n+1)
        f[1]=1
        f[2]=1

        for i in range(3,n+1):
            for j in range(1,i):
                res=i-j
                f[i]=max(f[res]*j,res*j,f[i]) #f[i]存储i至少被分为两份的乘积最大值

        return f[-1]

猜你喜欢

转载自blog.csdn.net/XindiOntheWay/article/details/82347390