Leetcode刷题笔记2 dp

213. House Robber II

dp, 首尾是环,转换成2部分

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

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Example 1:

Input: [2,3,2]
Output: 3
Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2),
             because they are adjacent houses.

Example 2:

Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
             Total amount you can rob = 1 + 3 = 4.
class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) == 1:
            return nums[0]
    
        def robHouse(nums, low, high):
            i1 = i2 = 0
            cur = 0
            for i in xrange(low, high):
                cur = max(i1, i2+nums[i])
                i2 = i1
                i1 = cur
            return cur
        
        return max(robHouse(nums, 0, len(nums)-1), robHouse(nums, 1, len(nums)))

368. Largest Divisible Subset 

LIS算法的变形,原理一样

Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies: Si % Sj = 0 or Sj % Si = 0.

If there are multiple solutions, return any subset is fine.

Example 1:

nums: [1,2,3]

Result: [1,2] (of course, [1,3] will also be ok)

Example 2:

nums: [1,2,4,8]

Result: [1,2,4,8]
class Solution(object):
    def largestDivisibleSubset(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        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做铺垫

Write a program to check whether a given number is an ugly number.

Ugly numbers are positive numbers whose prime factors only include 2, 3, 5.

Example 1:

Input: 6
Output: true
Explanation: 6 = 2 × 3

Example 2:

Input: 8
Output: true
Explanation: 8 = 2 × 2 × 2

Example 3:

Input: 14
Output: false 
Explanation: 14 is not ugly since it includes another prime factor 7.
class Solution(object):
    def isUgly(self, num):
        """
        :type num: int
        :rtype: bool
        """
        
        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

别人的写法:汗颜,学习了。

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

264. Ugly Number II

Write a program to find the n-th ugly number.

Ugly numbers are positive numbers whose prime factors only include 2, 3, 5

Example:

Input: n = 10
Output: 12
Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.
class Solution(object):
    def nthUglyNumber(self, n):
        """
        :type n: int
        :rtype: int
        """
        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]
        

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.

467. Unique Substrings in Wraparound String

Consider the string s to be the infinite wraparound string of "abcdefghijklmnopqrstuvwxyz", so s will look like this: "...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd....".

Now we have another string p. Your job is to find out how many unique non-empty substrings of p are present in s. In particular, your input is the string p and you need to output the number of different non-empty substrings of p in the string s.

Note: p consists of only lowercase English letters and the size of p might be over 10000.

Example 1:

Input: "a"
Output: 1

Explanation: Only the substring "a" of string "a" is in the string s.

Example 2:

Input: "cac"
Output: 2
Explanation: There are two substrings "a", "c" of string "cac" in the string s.

Example 3:

Input: "zab"
Output: 6
Explanation: There are six substrings "z", "a", "b", "za", "ab", "zab" of string "zab" in the string s.

思路:

  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):
        """
        :type p: str
        :rtype: int
        """
        dp = [0] * 26
        longest = 1
        
        for i in xrange(0, len(p)):
            if i == 0:
                longest = 1
            elif ord(p[i]) - ord(p[i-1]) in (1, -25):
                longest += 1 
            else:
                longest = 1
            index = ord(p[i]) - ord('a')
            dp[index] = max(dp[index], longest)
        
        return sum(dp)

139. Word Break

思路:

class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        
        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]

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):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        
        
        count, dp = [0 for i in nums], [1 for i in nums]
        
        for i in xrange(1, len(nums)):
            for j in xrange(0, i):
                if nums[j] < nums[i]:
                    dp[i] = max(dp[i], dp[j]+1)
                    
            for j in xrange(0, 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]
                
        return res if res else len(nums)

221. Maximal Square

DP

Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area.

Example:

Input: 

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

Output: 4

思路:

This problem can be solved by dynamic programming. They key to DP is the state equation. In this problem, we define the state as the maximal size of the square that can be achieved at point (i, j), denoted as dp[i][j]. Remember that we use size instead of square as the state (square = size * size).

Now let's try to come up with the formula for dp[i][j].

First, it is obvious that for the topmost row (i = 0) and the leftmost column (j = 0), dp[i][j] = matrix[i][j]. For example, if he topmost row of matrix is [1, 0, 0, 1], we immediately know that the first and last point can be a square of size 1 while the two middle points cannot make any square, giving a size of 0. Thus, dp = [1, 0, 0, 1], which is the same as matrix. The case is similar for the leftmost column. Till now, the boundary conditions of this DP problem are solved.

Let's move to the more general case for dp[i][j] in which i > 0 and j > 0. First of all, let's see a simple sub-case in which matrix[i][j] = 0. It is obvious that dp[i][j] = 0 since if matrix[i][j] = 0, no square will contain matrix[i][j]. According to our definition of dp[i][j]dp[i][j] is also 0.

Now we are almost done. The remaining sub-case is matrix[i][j] = 1. Suppose matrix = [[0, 1], [1, 1]], it is obvious that dp[0][0] = 0, dp[0][1] = dp[1][0] = 1, what about dp[1][1]? Well, to give a square of size larger than 1 in dp[1][1], all of its three neighbors (left, upper, upper-left) should be non-zero. In this case, the upper-left neighbor dp[0][0] = 0, so dp[1][1] can only be 1, which means that the square only contains matrix[1][1]. To summarize, dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1 in this case.

The state equations are finally as follows.

  1. dp[0][j] = matrix[0][j] (topmost row);
  2. dp[i][0] = matrix[i][0] (leftmost column);
  3. For i > 0 and j > 0: if matrix[i][j] = 0dp[i][j] = 0; if matrix[i][j] = 1dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1.
class Solution(object):
    def maximalSquare(self, matrix):
        """
        :type matrix: List[List[str]]
        :rtype: int
        """
        if not matrix:
            return 0
        
        row = len(matrix)
        col = len(matrix[0])
        
        size = [[0] * col for i in matrix]
        
        res = 0
        for i in xrange(row):
            for j in xrange(col):
                if col == 0:
                    size[i][j] = int(matrix[i][j])
                else:
                    size[i][j] = min(size[i-1][j], size[i][j-1], size[i-1][j-1]) + 1 if int(matrix[i][j]) else 0
                     
                res = max(res, size[i][j])
        
        return res*res

576. Out of Boundary Paths

There is an m by n grid with a ball. Given the start coordinate (i,j) of the ball, you can move the ball to adjacent cell or cross the grid boundary in four directions (up, down, left, right). However, you can at most move N times. Find out the number of paths to move the ball out of grid boundary. The answer may be very large, return it after mod 109 + 7.

Example 1:

Input:m = 2, n = 2, N = 2, i = 0, j = 0
Output: 6
Explanation:

Example 2:

Input:m = 1, n = 3, N = 3, i = 0, j = 1
Output: 12
Explanation:

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
    

猜你喜欢

转载自blog.csdn.net/Sengo_GWU/article/details/81603006