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.

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 递归:

# 递归
    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 递推:

10, 9, 2前面没有比他小的 = 1;5比2大,所以自己的解1 + 2的解1 = 2;3:自己的解1 + 2的解1=2; 7:2,5,3的最大长度 + 1= 2 + 1
# 递推
    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’)

在这里插入图片描述


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]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值