Leetcode刷題筆記-dp

44. Wildcard Matching

func isMatch(s string, p string) bool {
    dp := make([][]bool, len(s)+1)  // dp[s_idx][p_idx]
    for i := range dp {
        dp[i] = make([]bool, len(p)+1)
    }
    
    // init dp start from the table initiated as False everywhere but dp[0][0] = True.
    dp[0][0] = true
    
    
     // above miss to compute the situation when s is '' but p is not
    for j := 1; j <= len(p); j++ {
        if p[j-1] == '*' {
            dp[0][j] = dp[0][j-1]
        }
    } 
    // apply two rules
    // 1. if s[s_idx-1] = p[p_idx-1]   dp[i][j] i: idx of s, j: idx of p   = dp[i-1][j-1]
    // 2. if p[p_idx-1] = '*' and dp[i][j-1] = true or dp[i-1][j-1], dp[idx][j] = true for all idx >= i-1
    // case:   s = a p = a* dp[1][2] = dp[1][1], s = a p = * dp[1][1] = dp[0][1]
    for i := 1; i <= len(s); i++ {
        for j := 1; j <= len(p); j++ {
            if dp[i][j] == true {  // because of 下面的 rule2
                continue
            }
            if s[i-1] == p[j-1] || p[j-1] == '?'{  // rule1
                dp[i][j] = dp[i-1][j-1]
            }else if p[j-1] == '*' { // rule2  
                if dp[i][j-1] == true || dp[i-1][j] == true {
                    for idx := i; idx <= len(s); idx++ {
                        dp[idx][j] = true
                    }
                }
            }
        }
    }
    
    return dp[len(s)][len(p)]
    
}
func isMatch(s string, p string) bool {
    // mem[i][j] means isMatch(s[:i], p[:j])
    mem := make([][]bool, len(s)+1)
    for i := range mem {
        mem[i] = make([]bool, len(p)+1)
    }
	
	// init bound, mem[n][0] is false while n > 0
    mem[0][0] = true
    for j := 1; j <= len(p); j++ {
        if p[j-1] == '*' {
            mem[0][j] = mem[0][j-1]
        }
    }
    
    for i := 1; i <= len(s); i++ {
        for j := 1; j <= len(p); j++ {
            if p[j-1] == '*' {
// mem[i][j] = mem[i][j-1] 則* 匹配空字符串, =mem[i-1][j]則j匹配任意當前字符串
                mem[i][j] = mem[i][j-1] || mem[i-1][j]
            } else if p[j-1] == '?' || p[j-1] == s[i-1] {
                mem[i][j] = mem[i-1][j-1]
            }
        }
    }
    
    return mem[len(s)][len(p)]
}

410. Split Array Largest Sum

參考

https://leetcode.com/problems/split-array-largest-sum/discuss/89816/DP-Java

https://leetcode.com/problems/split-array-largest-sum/discuss/328544/Two-Go-solutions-First-Binary-Search-Second-Dynamic-Programming

func splitArray(nums []int, m int) int {
    // dp
    length := len(nums)
    dp := make([][]int, length+1)
    // init dp[][]
    for i := 0; i <= length; i++ {
        dp[i] = make([]int, m+1)
        for j := 0; j <= m; j++ {
            dp[i][j] = math.MaxInt32
        }
    }
    
    preSum := make([]int, length+1)
    for i, v := range nums {
        preSum[i+1] = preSum[i] + v
    }
    
    dp[0][0] = 0
    for i:= 1; i <= length; i++ {
        for j := 1; j <= m; j++ {
            for k := 0; k < i; k++ {  //  0 <= k < i
                // dp[i][j] nums[0]~nums[i] split to j parts 
                dp[i][j] = min(dp[i][j], max(dp[k][j-1], preSum[i] - preSum[k]))  
            }
        }
    }
    return dp[length][m]
        
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

func max(a, b int) int {
    if a < b {
        return b
    }
    return a
}

312. Burst Balloons

dp[i][j] in here means, the maximum coins we get after we burst all the balloons between i+1 and j-1 in the array 

class Solution(object):
    def maxCoins(self, nums):
        nums = [1] + nums + [1]
        n = len(nums)
        dp = [[0] * n for _ in xrange(n)]
        print n
        for gap in range(2, n):
            for left in range(0, n-gap):
                right = left + gap
                for i in range(left+1, right):  # left, right are not included for the last burst, they are the edges 
                    dp[left][right] = max(dp[left][right], 
                                         nums[left]*nums[i]*nums[right] + dp[left][i] + dp[i][right])
        return dp[0][-1]

 

1000. Minimum Cost to Merge Stones

https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1000-minimum-cost-to-merge-stones/

class Solution(object):
    def mergeStones(self, stones, K):
        n = len(stones)
        if (n-1) % (K-1): return -1
        inf = float('inf')
        preSum = [0] * (n+1)
        for i in xrange(n):
            preSum[i+1] = stones[i] + preSum[i]
        # dp[i][j][k] := min cost to merge subarray i~j into k piles.
        dp = [[[inf] * (K+1) for _ in xrange(n)] for _ in xrange(n)]
        for i in xrange(n):
            dp[i][i][1] = 0
            
        for l in xrange(2, n+1):  # subproblem length
            for i in xrange(n-l+1):
                j = i + l - 1 
                for k in xrange(2, K+1):
                    for m in xrange(i, j):
                        dp[i][j][k] = min(dp[i][j][k], dp[i][m][1] + dp[m+1][j][k-1])
                    if dp[i][j][K] < inf:
                        dp[i][j][1] = dp[i][j][K] + preSum[j+1] - preSum[i]
        
        return dp[0][-1][1]

 

446. Arithmetic Slices II - Subsequence

class Solution(object):
    def numberOfArithmeticSlices(self, A):
        # dp[i][j] the number of arithmetic ending with idx ith, increment is j 
        dp = [collections.defaultdict(int) for _ in A]
        re = 0
        for i in xrange(len(A)):
            for j in xrange(i):
                dp[i][A[i]-A[j]] += 1  # 把2個的也加入
                if A[i]-A[j] in dp[j]:
                    dp[i][A[i]-A[j]] += dp[j][A[i]-A[j]]  # dp[j]是至少兩個的, dp[i]是比dp[j]多一個的, 因爲上面加1了,所以這裏不加1
                    re += dp[j][A[i]-A[j]] # dp[j][A[i]-A[j]] + 1 - 1 
        return re

 

329. Longest Increasing Path in a Matrix

class Solution(object):
    def longestIncreasingPath(self, matrix):
        def dfs(i, j):
            if not dp[i][j]:
                val = matrix[i][j]
                dp[i][j] = 1 + max(dfs(i-1, j) if i > 0 and matrix[i-1][j] < val else 0,  # dfs不是dp
                                   dfs(i+1, j) if i+1 < len(matrix) and matrix[i+1][j] < val else 0,
                                   dfs(i, j-1) if j > 0 and matrix[i][j-1] < val else 0,
                                   dfs(i, j+1) if j+1 < len(matrix[0]) and matrix[i][j+1] < val else 0)
                
            return dp[i][j]
        
        if not matrix or not matrix[0]: return 0
        dp = [[0] * len(matrix[0]) for _ in xrange(len(matrix))]
        return max(dfs(i, j) for i in xrange(len(matrix)) for j in xrange(len(matrix[0])))

518. Coin Change 2

class Solution(object):
    def change(self, amount, coins):
        """
        :type amount: int
        :type coins: List[int]
        :rtype: int
        """
        dp = [0] * (amount+1)
        dp[0] = 1  # so that dp[amou-coin=0] = 1
        for c in coins:
            for amou in xrange(1, amount+1):
                if amou >= c:
                    dp[amou] += dp[amou-c]
        
        return dp[amou]

322. Coin Change 

class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        
        dp = collections.defaultdict(int)
        coins = sorted(coins)
        for money in xrange(1, amount+1):
            minCoins = 5000
            for coin in coins:
                if money-coin>=0 and dp[money-coin] != -1:
                    minCoins = min(dp[money-coin], minCoins)
            if minCoins == 5000:
                dp[money] = -1
            else:
                dp[money] = minCoins + 1
        return dp[amount]

 

174. Dungeon Game

第一次解,超時:

class Solution(object):       
     def dfs(i, j, val, minVal):
            val += d[i][j]
            
            if i == len(d) - 1 and j == len(d[0])-1:
                return minVal
            
            rightward = float('-inf')
            if j + 1 <= len(d[0]) - 1 :
                rightward = dfs(i, j+1, val, minVal)
            
            downward = float('-inf')
            if i + 1 <= len(d) - 1:
                downward = dfs(i+1, j, val, minVal)
            
            return max(rightward, downward) 
        
        re = dfs(0, 0, 0, 0)
        
        return -re + 1 if re <= 0 else 1

DP, 自底向上 

class Solution(object):
    def calculateMinimumHP(self, d):
        # hp[i][j] to store the min hp needed at position (i, j)
        # adding dummy row and column to hp would make the code cleaner
        r, c = len(d), len(d[0])
        hp = [[sys.maxint] * (c+1) for _ in xrange(r+1)]
        hp[r][c-1] = 1
        hp[r-1][c] = 1
        for i in xrange(r-1, -1, -1):
            for j in xrange(c-1, -1, -1):
                need = min(hp[i+1][j], hp[i][j+1]) - d[i][j]
                # 這裏負數要設爲1,因爲如左下角10往上走的時候,纔會是1+5+2
                hp[i][j] = need if need > 0 else 1
        return hp[0][0]

 

213. House Robber II

dp, 首尾是環,轉換成2部分

  1. Rob houses 0 to n - 2;
  2. Rob houses 1 to n - 1.

 

class Solution(object):
    def rob(self, nums):
        if len(nums) == 1:
            return nums[0]
    
        def robHouse(nums, low, high):
            pre2 = pre1 = 0
            cur = 0
            for i in xrange(low, high):
                cur = max(pre1, pre2+nums[i])
                pre2 = pre1
                pre1 = cur
            return cur
        
        return max(robHouse(nums, 0, len(nums)-1), robHouse(nums, 1, len(nums)))

368. Largest Divisible Subset 

LIS算法的變形,原理一樣

 

class Solution(object):
    def largestDivisibleSubset(self, nums):
        if not nums:
            return []
        nums = sorted(nums)
        dp = [[nums[0]] for i in nums]
        res = [nums[0]]
        for i in xrange(1, len(nums)):
            dp[i] = [nums[i]]
            for j in xrange(0, i):
                if nums[i] % nums[j] == 0:
                    dp[i] = dp[j] + [nums[i]] if len(dp[j]) >= len(dp[i]) else dp[i]
            res = dp[i] if len(res) < len(dp[i]) else res
        return res

263. Ugly Number

給ugly Number 2做鋪墊

class Solution(object):
    def isUgly(self, num):
        rest = num
        if rest == 0:
            return False
        while rest != 1:
            if rest % 2 == 0:
                rest /= 2
            elif rest % 3 == 0:
                rest /= 3
            elif rest % 5 == 0:
                rest /= 5
            else:
                return False
            
        return True

別人的寫法:汗顏,學習了。 num%p == 0 < num 相當於  Num%p == 0 and num%p < num

for p in 2, 3, 5:
    while num % p == 0 < num:
        num /= p
return num == 1

264. Ugly Number II

Explanation:

The key is to realize each number can be and have to be generated by a former number multiplied by 2, 3 or 5
e.g.
1 2 3 4 5 6 8 9 10 12 15..
what is next?
it must be x * 2 or y * 3 or z * 5, where x, y, z is an existing number.

How do we determine x, y, z then?
apparently, you can just traverse the sequence generated by far from 1 ... 15, until you find such x, y, z that x * 2, y * 3, z * 5 is just bigger than 15. In this case x=8, y=6, z=4. Then you compare x * 2, y * 3, z * 5 so you know next number will be x * 2 = 8 * 2 = 16.
k, now you have 1,2,3,4,....,15, 16,

Then what is next?
You wanna do the same process again to find the new x, y, z, but you realize, wait, do I have to
traverse the sequence generated by far again?

NO! since you know last time, x=8, y=6, z=4 and x=8 was used to generate 16, so this time, you can immediately know the new_x = 9 (the next number after 8 is 9 in the generated sequence), y=6, z=4.
Then you need to compare new_x * 2, y * 3, z * 5. You know next number is 9 * 2 = 18;

And you also know, the next x will be 10 since new_x = 9 was used this time.
But what is next y? apparently, if y=6, 6*3 = 18, which is already generated in this round. So you also need to update next y from 6 to 8.

Based on the idea above, you can actually generated x,y,z from very beginning, and update x, y, z accordingly. It ends up with a O(n) solution.

class Solution(object):
    def nthUglyNumber(self, n):
        dp = [1]*(n+1)
        n2 = n3 = n5 = 1

        for i in xrange(2, n+1):
            dp[i] = min(dp[n2]*2, dp[n3]*3, dp[n5]*5)
            
            if dp[n2]*2 == dp[i]:
                n2 += 1
            if dp[n3]*3 == dp[i]:
                n3 += 1
            if dp[n5]*5 == dp[i]:
                n5 += 1
        return dp[n]

467. Unique Substrings in Wraparound String

 

思路:

  1. The max number of unique substring ends with a letter equals to the length of max contiguous substring ends with that letter. Example "abcd", the max number of unique substring ends with 'd' is 4, apparently they are "abcd", "bcd", "cd" and "d".
  2. If there are overlapping, we only need to consider the longest one because it covers all the possible substrings. Example: "abcdbcd", the max number of unique substring ends with 'd' is 4 and all substrings formed by the 2nd "bcd" part are covered in the 4 substrings already.
  3. No matter how long is a contiguous substring in p, it is in s since s has infinite length.
  4. Now we know the max number of unique substrings in p ends with 'a', 'b', ..., 'z' and those substrings are all in s. Summary is the answer, according to the question.
class Solution(object):
    def findSubstringInWraproundString(self, p):
        dp = [0] * 26
        re = 0
        pre = 0
        for i in xrange(len(p)):
            if (ord(p[i]) - ord(p[i-1])) in (1, -25):
                cur = pre + 1
            else:
                cur = 1
            pre = cur
            val = ord(p[i])-ord('a')
            dp[val] = max(dp[val], cur)
        return sum(dp)

139. Word Break

思路:

class Solution(object):
    def wordBreak(self, s, wordDict):
        dp = [False] * len(s)
        for i in xrange(0, len(s)):
            for w in wordDict:
                if i-len(w)+1 >= 0:
                    if w == s[i-len(w)+1: i+1] and (dp[i-len(w)] or i-len(w) == -1):
                        dp[i] = True
        return dp[-1]

BFS

I use BFS to avoid useless states calculation like someone did in Coin Change. I do not check every substring but I check the substring whose length is possible (I store all distinct length of words in a list). Thus, no need to check backward from the current position one by one.

class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: Set[str]
        :rtype: bool
        """
        queue = [0]
        slen = len(s)
        lenList = [l for l in set(map(len,wordDict))]
        visited = [0 for _ in range(0, slen + 1)]
        while queue:
            tmpqueue = []
            for start in queue:
                for l in lenList:
                    if s[start:start+l] in wordDict:
                        if start + l == slen:
                            return True
                        if visited[start + l] == 0:
                            tmpqueue.append(start+l)
                            visited[start + l] = 1
            queue, tmpqueue = tmpqueue, []
        return False

 

673. Number of Longest Increasing Subsequence


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].

Example 2:

Input: [2,2,2,2,2]
Output: 5
Explanation: The length of longest continuous increasing subsequence is 1, and there are 5 subsequences' length is 1, so output 5.

思路:

The idea is to use two arrays len[n] and cnt[n] to record the maximum length of Increasing Subsequence and the coresponding number of these sequence which ends with nums[i], respectively. That is:

len[i]: the length of the Longest Increasing Subsequence which ends with nums[i].
cnt[i]: the number of the Longest Increasing Subsequence which ends with nums[i].

Then, the result is the sum of each cnt[i] while its corresponding len[i] is the maximum length.

class Solution(object):
    def findNumberOfLIS(self, nums):
        if not nums:
            return 0
        count, dp = [0 for i in nums], [1 for i in nums]
        
        for i in xrange(len(nums)):
            for j in xrange(i):
                if nums[j] < nums[i]:
                    dp[i] = max(dp[i], dp[j]+1)
                    
            for j in xrange(i):
                if nums[j] < nums[i] and dp[i]-1 == dp[j]:
                    count[i] += count[j] if count[j] else 1
    
        res = 0
        for i in xrange(len(nums)):
            if dp[i] == max(dp):
                res += count[i] if count[i] else 1
        return res

576. Out of Boundary Paths

 

Note:

  1. Once you move the ball out of boundary, you cannot move it back.
  2. The length and height of the grid is in range [1,50].
  3. N is in range [0,50].
  1. 這道題乍一看很像一個標準的bfs,因爲限定最多隻能移動N次,我們只要bfs依次遍歷發現出界就+1,當bfs的深度大於N的時候break。當然理論上是沒有任何問題的,確實能得出正確答案,但是這裏N的取值範圍達到了50,我們對任意一個點bfs有四個方向(可以走回頭路),那麼複雜度達到了4^N,顯然會超時。當然我會在文章後面給出bfs的做法,畢竟這是可以處理N比較小的情況的解法,讓大家更熟悉bfs的套路。
  2. 我不知道你們有沒有這種感覺,一般看到這個mod 1e9+7,這道題8成就是dp了,而且就是那種每個dp值你都得mod一下再去進行運算的那種。我覺得這算一個小技巧吧,看到mod 1e9+7就要想到dp。
  3. 顯然,這裏dp很好定義,我們定義dp[(i,j,N)]表示從i,j出發,最多走N步情況下滿足題意的路徑數量,那麼我們所求也就是dp[(i,j,N)]。根據我們上面說的bfs的思路,遞推式可得:
    dp[(i,j,N)] = dp[(i+1,j,N-1)] + dp[(i-1,j,N-1)] + dp[(i,j+1,N-1)] + dp[(i,j-1,N-1)]
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
        """
        mod = 10**9 + 7
        cache = collections.defaultdict(int)
        
        def helper(N, i, j, cache):
            if (i, j, N) in cache:
                return cache[(i, j, N)]
            
            if 0<=i<m and 0<=j<n:
                if N == 0:
                    cache[(i, j, N)] = 0
                    return 0
                
                for x, y in ((i-1, j), (i+1, j), (i, j-1), (i, j+1)):
                    cache[(i, j, N)] += helper(N-1, x, y, cache)
                
                return cache[(i, j, N)] % mod
            else:
                cache[(i, j, N)] = 1
                return 1
            
        return helper(N, i, j, cache)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def findPaths(m,n,N,i,j):
    mod = 10**9 + 7
    Q = collections.deque([(i,j,0)])
    res = 0
    while Q:
        x,y,step = Q.popleft()
        if step > N: break
        if 0<=x<m and 0<=y<n:
            Q.append((x+1,y,step+1))
            Q.append((x-1,y,step+1))
            Q.append((x,y+1,step+1))
            Q.append((x,y-1,step+1))
        else:
            res += 1
    return res % mod

 787. Cheapest Flights Within K Stops

Dijkstra's algorithm 每次更新剩餘點到起始點的價格。

There are n cities connected by m flights. Each fight starts from city and arrives at v with a price w.

Now given all the cities and fights, together with starting city src and the destination dst, your task is to find the cheapest price from src to dst with up to k stops. If there is no such route, output -1.

Example 1:
Input: 
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 1
Output: 200
Explanation: 
The graph looks like this:


The cheapest price from city 0 to city 2 with at most 1 stop costs 200, as marked red in the picture.
Example 2:
Input: 
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 0
Output: 500
Explanation: 
The graph looks like this:


The cheapest price from city 0 to city 2 with at most 0 stop costs 500, as marked blue in the picture.
class Solution(object):
    def findCheapestPrice(self, n, flights, src, dst, K):
        """
        :type n: int
        :type flights: List[List[int]]
        :type src: int
        :type dst: int
        :type K: int
        :rtype: int
        """
        prices = collections.defaultdict(dict)
        
        for a, b, p in flights:
            prices[a][b] = p
        
        heap = [(0, src, K+1)]
        while heap:
            price, curPlace, steps = heapq.heappop(heap)
            if curPlace == dst:
                return price
            
            if steps > 0:
                for arr in prices[curPlace]:
                    heapq.heappush(heap, (price+prices[curPlace][arr], arr, steps-1))
        return -1
    

304. Range Sum Query 2D - Immutable 

Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).

Range Sum Query 2D
The above rectangle (with the red border) is defined by (row1, col1) = (2, 1) and (row2, col2) = (4, 3), which contains sum = 8.

Example:

Given matrix = [
  [3, 0, 1, 4, 2],
  [5, 6, 3, 2, 1],
  [1, 2, 0, 1, 5],
  [4, 1, 0, 1, 7],
  [1, 0, 3, 0, 5]
]

sumRegion(2, 1, 4, 3) -> 8
sumRegion(1, 1, 2, 2) -> 11
sumRegion(1, 2, 2, 4) -> 12
class NumMatrix(object):

    def __init__(self, matrix):
        """
        :type matrix: List[List[int]]
        """
        dpSum = [[0]*len(matrix[0]) for i in matrix]
        
        for i in xrange(len(matrix)):
            for j in xrange(len(matrix[0])):
                if j-1>=0:
                    dpSum[i][j] += dpSum[i][j-1]
                for row in xrange(0, i+1):
                     dpSum[i][j] += matrix[row][j]
        self.dpSum = dpSum

    def sumRegion(self, row1, col1, row2, col2):
        """
        :type row1: int
        :type col1: int
        :type row2: int
        :type col2: int
        :rtype: int
        """
        
        res = self.dpSum[row2][col2] 
        if col1 - 1 >= 0:
            res -= self.dpSum[row2][col1-1]
        if row1 -1 >= 0:
            res -= self.dpSum[row1-1][col2]
        if col1 - 1 >= 0 and row1 -1 >= 0:
            res += self.dpSum[row1-1][col1-1]
        return res

# Your NumMatrix object will be instantiated and called as such:
# obj = NumMatrix(matrix)
# param_1 = obj.sumRegion(row1,col1,row2,col2)

 

464. Can I Win

遊戲的可以整理一篇,都是暴力破解(遞歸)加記憶。DP用於記錄計算過的路徑避免重複計算。

class Solution(object):
    def canIWin(self, maxChoosableInteger, desiredTotal):
        choose = tuple(i for i in xrange(1, maxChoosableInteger+1))
        visited = {}
        if sum(choose) < desiredTotal: return False  

        def helper(target, choose, visited):
            if len(choose) == 0:
                return False
            if choose in visited: return visited[choose]
            if target - max(choose) <= 0:
                visited[choose] = True
                return True
            for n in choose:
                leftChoose = tuple(x for x in choose if x!=n)
                # 對方輸,我方就贏
                if not helper(target-n, leftChoose, visited):
                    visited[choose] = True
                    return True
                 
            visited[choose] = False
            return False
        
        return helper(desiredTotal, choose, visited)

 

 

523. Continuous Subarray Sum 

思路:

暴力破解就不說了,

在討論裏有個大神給出了時間複雜度是O(nn)的解法,他的思路非常巧妙,用了數學上的知識,下面給出他的解法的原理: 
假設: 

a[i]+a[i+1]+...+a[j]=n1k+q;a[i]+a[i+1]+...+a[j]=n1k+q;


如果存在一個n 

n>j且a[i]+a[i+1]+...+a[j]+...+a[n]=n2k+q;n>j且a[i]+a[i+1]+...+a[j]+...+a[n]=n2k+q;


那麼 

a[j+1]+...+a[n]=(n2−n1)ka[j+1]+...+a[n]=(n2−n1)k


因此利用這一結果,可以從序列第一個元素開始遍歷,不斷累加上當前的元素,並求出當前和除以k後的餘數,用一個映射記錄該餘數出現時的下標,如果同一個餘數出現了兩次,並且兩次出現的下標之差大於1,那麼就表示在這兩個座標之間的元素之和是k的倍數,因此就可以返回true,否則最後返回false。 
需要注意的兩個地方: 
1. k可能取0,所以只有當k不爲0時纔對當前的和求餘,同時針對於nums = [0, 0], k = 0的情況,需要添加一個初始映射(0, -1)來確保結果的正確。 
2. 下標之差至少爲2纔算是正確的情況,因爲題目要求子序列長度至少爲2,以上面的例子就是n至少等於j+2。 
具體實現見下面參考代碼。

class Solution(object):
    def checkSubarraySum(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: bool
        """
        if len(nums) < 2:
            return False
        
        if k == 0:
            for i in range(0, len(nums) - 1):
                if nums[i] == 0 and nums[i+1] == 0:
                    return True
            return False
        
        k = abs(k)
        if len(nums) >= 2*k:
            return True
        
        Sum = [0]
        for x in nums:
            Sum.append((Sum[-1]+x)%k)
            
        Dict = {}
        for i in xrange(len(Sum)):
            if Dict.has_key(Sum[i]):
                if i - Dict[Sum[i]] >= 2:
                    return True
            else:
                Dict[Sum[i]] = i
            
        return False
        

91. Decode Ways 


A message containing letters from A-Z is being encoded to numbers using the following mapping:

'A' -> 1
'B' -> 2
...
'Z' -> 26

Given a non-empty string containing only digits, determine the total number of ways to decode it.

Example 1:

Input: "12"
Output: 2
Explanation: It could be decoded as "AB" (1 2) or "L" (12).

Example 2:

Input: "226"
Output: 3
Explanation: It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).

i指的是字符串長度。

class Solution(object):
    def numDecodings(self, s):
        """
        :type s: str
        :rtype: int
        """
        if s[0] == '0':
            return 0
        
        dp = [0 for i in xrange(len(s)+1)]
        dp[0] = 1
        dp[1] = 0 if s[0] == '0' else 1
        for i in xrange(2, len(s)+1):
            one = int(s[i-1])
            two = int(s[i-2:i])
            
            if 1 <= one:
                dp[i] = dp[i-1]
                
            if 10 <= two <= 26:
                dp[i] += dp[i-2]
            
        return dp[-1]

639. Decode Ways II

 等於切出最後一位和最後2位,看1位的幾種和2位的幾種 分別乘以對應的dp[i-1], dp[i-2]

這題的解法上一題也可以用。

** = 11-19, 21-26.  如果** 是比如 37的話,應該是在one裏面

class Solution(object):
    def numDecodings(self, s):
        one = {'0': 0, '1': 1, '2': 1, '3': 1, '4': 1, '5': 1, '6': 1, '7': 1, '8': 1, '9': 1, '*': 9}
        two = {'10': 1, '11': 1, '12': 1, '13': 1, '14': 1, '15': 1, '16': 1, '17': 1, '18': 1, '19': 1, '20': 1, '21': 1,
       '22': 1, '23': 1, '24': 1, '25': 1, '26': 1, '*0': 2, '*1': 2, '*2': 2, '*3': 2, '*4': 2, '*5': 2, '*6': 2,
       '*7': 1, '*8': 1, '*9': 1, '1*': 9, '2*': 6, '**': 15}
        
        dp = [1, one.get(s[0])]  # dp[i-2], dp[i-1]
        
        for i in xrange(1, len(s)):
            dp = dp[1], (one.get(s[i]) * dp[1] + two.get(s[i-1: i+1], 0) * dp[0]) % 1000000007
        return dp[-1]

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章