LeetCode刷题碎碎念(三):DP 2
DP
I: n, S = O(n), T = O(n*sqrt(n))
279. Perfect Squares (Medium)
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, …) which sum to n.
Example 1:
Input: n = 12
Output: 3
Explanation: 12 = 4 + 4 + 4.
def numSquares(self, n):
"""
:type n: int
:rtype: int
"""
dp = [0]*(n+1)
for i in range(1, n+1):
dp[i] = min(dp[i-j*j] for j in range(1, int(i**0.5)+1)) + 1
return dp[n]
All we need is a better way to implement the formula.
numSquares(n) = min( numSquares(n-k) + 1 ) ∀k∈{square numbers}
First we need to calculate all the values before n, i.e. numSquares(n-k) ∀k∈{square numbers}. If we have already kept the solution for the number n-k in somewhere, we then would not need to resort to the recursive calculation which prevents the stack overflow.
![](https://i-blog.csdnimg.cn/blog_migrate/a0e841466068f07cd06a867111f94b9a.png)
I: O(n), S = O(n), T = O(n^2)
139. Word Break (Medium)
Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
Example 1:
Input: s = “leetcode”, wordDict = [“leet”, “code”]
Output: true
Explanation: Return true because “leetcode” can be segmented as “leet code”.
string中间取一个点,看右半部分是否在字典中;再对左半部分取一个点,看其右半部分是否在字典里…如果全都在字典里,True
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
def canBreak(s, m, wordDict):
# m is to memory the ans to each substring
# m: { 'leet': True
# 'code': True
# 'what?': False }
if s in m: return m[s]
if s in wordDict:
m[s] = True
return True
for i in range(1, len(s)):
r = s[i:]
if r in wordDict and canBreak(s[0:i], m, wordDict):
m[s] = True
return True
m[s] = False
return False
return canBreak(s, {}, wordDict)
300. Longest Increasing Subsequence (Medium)
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.
递推:数学上的概念,主要指递推式、递推数列或递推函数。一个数列的下一项由它前面几项的一种运算(或函数)构成,如 a[n]=a[n−1]+a[n−2]。
递归:计算机中的概念,主要指计算机上的递归函数,(计算机中的‘函数’不同于数学上的‘函数’,这里指一段代码),即指会调用自己的函数。
Solution 1 递归:
![](https://i-blog.csdnimg.cn/blog_migrate/08e8e1e582f41934d1ee56d9a0021610.png)
# 递归
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
if n == 0: return 0
f = [0] * n # f[r]: Length of LIS ends with r
ans = 0
def LIS(nums, r):
if r == 0: return 1 # only one number
if f[r] > 0: return f[r]
ans = 1
# 前面是否有更小的数
for i in range(r): # 枚举所有比当前subarray短的subarray
if nums[r] > nums[i]: # 最后一个字母大于枚举的subarray的最后一个数
ans = max(ans, LIS(nums, i)+1) # 把这个数加在之前的subarray后面
f[r] = ans
return f[r]
# nums的第一位到最后一位一次寻找
for i in range(n):
ans = max(ans, LIS(nums, i))
return ans
Solution 2 递推:
![](https://i-blog.csdnimg.cn/blog_migrate/e395de74dc700c35188c71785a33039d.png)
# 递推
def lengthOfLIS(self, nums):
if not nums: return 0
n = len(nums)
f = [1] * n
for i in range(1, n):
for j in range(i):
if nums[i] > nums[j]:
f[i] = max(f[i], f[j]+1)
return max(f)
Solution 3 Binary Search:
673. Number of Longest Increasing Subsequence (Medium)
Given an unsorted array of integers, find the number of longest increasing subsequence.
Example 1:
Input: [1,3,5,4,7]
Output: 2
Explanation: The two longest increasing subsequence are [1, 3, 4, 7] and [1, 3, 5, 7].
NLIS(A[n])结果等于所有长度小于n的序列的结果的合,即在这之前的所有的合。
Solution 1 递归:
def findNumberOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
if n == 0: return 0
c = [0] * n # c[i] number of LIS ends with nums[i] NLIS
l = [0] * n # l[i] length of LIS ends with nums[i] LIS
max_len = 0
def length(nums, n):
if n == 0: return 1 # only one number
if l[n] > 0: return l[n]
max_len = 1
# 前面是否有更小的数
for i in range(n): # 枚举所有比当前subarray短的subarray
if nums[n] > nums[i]: # 最后一个字母大于枚举的subarray的最后一个数
max_len = max(max_len, length(nums, i)+1) # 把这个数加在之前的subarray后面
l[n] = max_len
return l[n]
def count(nums, n):
if n == 0: return 1
if c[n] > 0: return c[n]
total_count = 0
l = length(nums, n)
for i in range(n):
if nums[n] > nums[i] and length(nums, i) == l-1:
total_count += count(nums, i)
if total_count == 0:
total_count = 1
c[n] = total_count
return c[n]
# finding the length of LIS
for i in range(n):
max_len = max(max_len, length(nums, i))
# 检查之前求得的长度(不同结尾)是否都==最大长度,然后计数
ans = 0
for i in range(n):
if length(nums, i) == max_len:
ans += count(nums, i)
return ans
Solution 2 递推:
def findNumberOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
if n == 0: return 0
c = [1] * n
l = [1] * n
for i in range(1, n): # 从开始到结尾作为end的subarry
for j in range(i): # 找他的所有前序subarray
if nums[i] > nums[j]:
if l[j] + 1 > l[i]: # 找到新的LIS
l[i] = l[j] + 1
c[i] = c[j]
elif l[j] + 1 == l[i]:
c[i] += c[j]
max_len = max(l)
ans = 0
for i in range(n):
if l[i] == max_len:
ans += c[i]
return ans
1048. Longest String Chain (Medium)
Given a list of words, each word consists of English lowercase letters.
Let’s say word1 is a predecessor of word2 if and only if we can add exactly one letter anywhere in word1 to make it equal to word2. For example, “abc” is a predecessor of “abac”.
A word chain is a sequence of words [word_1, word_2, …, word_k] with k >= 1, where word_1 is a predecessor of word_2, word_2 is a predecessor of word_3, and so on.
Return the longest possible length of a word chain with words chosen from the given list of words.
Example 1:
Input: [“a”,“b”,“ba”,“bca”,“bda”,“bdca”]
Output: 4
Explanation: one of the longest word chain is “a”,“ba”,“bda”,“bdca”.
def longestStrChain(self, words):
dp = {}
for w in sorted(words, key=len): # Sort the words by word's length
# For each word, loop on all possible previous word with 1 letter missing.
# If we have seen this previous word, update the longest chain for the current word.
dp[w] = max(dp.get(w[:i] + w[i + 1:], 0) + 1 for i in xrange(len(w)))
return max(dp.values())
96. Unique Binary Search Trees (Medium)
Given n, how many structurally unique BST’s (binary search trees) that store values 1 … n?
Example:
Input: 3
Output: 5
Explanation:
Given n = 3, there are a total of 5 unique BST’s:
1 3 3 2 1
\ / / / \
3 2 1 1 3 2
/ / \
2 1 2 3
所有点作为root的情况加在一起。
def numTrees(self, n):
"""
:type n: int
:rtype: int
"""
G = [0]*(n+1)
G[0], G[1] = 1, 1
for i in range(2, n+1):
for j in range(1, i+1):
G[i] += G[j-1] * G[i-j]
return G[n]
I: O(n), S = O(2^n), T = O(2^n)
89. Gray Code (Medium)
The gray code is a binary numeral system where two successive values differ in only one bit.
Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0.
Example 1:
Input: 2
Output: [0,1,3,2]
Explanation:
00 - 0
01 - 1
11 - 3
10 - 2
Gary code: i 异或 ( i / 2 ), i ^ (1 << n)
results = [0]
for i in range(n):
results += [x + pow(2, i) for x in reversed(results)]
return results
pow(x, y) is equal to x^y
pow(x, y, z) is equal to x^y % z
72. Edit Distance (Hard)
Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2.
You have the following 3 operations permitted on a word:
Insert a character
Delete a character
Replace a character
Example 1:
Input: word1 = “horse”, word2 = “ros”
Output: 3
Explanation:
horse -> rorse (replace ‘h’ with ‘r’)
rorse -> rose (remove ‘r’)
rose -> ros (remove ‘e’)
![](https://i-blog.csdnimg.cn/blog_migrate/1c4af84bdd8e28e1c9392eaba6ae2dfb.png)
def minDistance(self, word1: str, word2: str) -> int:
# Recursion + memorization
l1 = len(word1)
l2 = len(word2)
d = [[0] * (l2+1) for _ in range(l1+1)]
if l1 == 0 or l2 ==0:
return l1 + l2
for i in range(l1+1):
d[i][0] = i
for j in range(l2+1):
d[0][j] = j
for i in range(1, l1+1):
for j in range(1, l2+1):
if word1[i-1] != word2[j-1]:
d[i][j] = min(d[i-1][j] + 1, d[i][j-1] + 1, d[i-1][j-1] + 1)
else:
d[i][j] = min(d[i-1][j] + 1, d[i][j-1] + 1, d[i-1][j-1])
return d[l1][l2]