- Largest rectangle in Histogram
- Maximal rectangle
- Unique Binary Search Trees
- Unique Binary Search Trees II
- Triangle
- Range sum query
- Best time to buy and sell stock III
- Best time to buy and sell stock IV
- Distinct Subsequence
- Longest Valid Parentheses
- word break
- word break II
- Min cost climbing stairs
- Ugly number
- Interleaving String
- Integer break
参考: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/
卡特兰数
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]