题号 73、64、63、62、59、56、55、54、48

73. Set Matrix Zeroes

Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.

click to show follow up. Follow up:

Did you use extra space? A straight forward solution using O(mn) space is probably a bad idea. A simple improvement uses O(m + n) space, but still not the best solution. Could you devise a constant space solution?

64. Minimum Path Sum

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

Note: You can only move either down or right at any point in time.

Example:

Input:
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
Output: 7
Explanation: Because the path 1→3→1→1→1 minimizes the sum.
# O(m*n) space
def minPathSum(self, grid):
    if not grid:
        return
    r, c = len(grid), len(grid[0])
    dp = [[0 for _ in xrange(c)] for _ in xrange(r)]
    dp[0][0] = grid[0][0]
    for i in xrange(1, r):
        dp[i][0] = dp[i-1][0] + grid[i][0]
    for i in xrange(1, c):
        dp[0][i] = dp[0][i-1] + grid[0][i]
    for i in xrange(1, len(grid)):
        for j in xrange(1, len(grid[0])):
            dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
    return dp[-1][-1]

# O(2*n) space
def minPathSum2(self, grid):
    if not grid:
        return
    r, c = len(grid), len(grid[0])
    pre = cur = [0] * c
    pre[0] = grid[0][0]
    for i in xrange(1, c):
        pre[i] = pre[i-1] + grid[0][i]
    for i in xrange(1, r):
        cur[0] = pre[0] + grid[i][0]
        for j in xrange(1, c):
            cur[j] = min(cur[j-1], pre[j]) + grid[i][j]
        pre = cur
    return cur[-1]

# O(n) space
def minPathSum(self, grid):
    if not grid:
        return
    r, c = len(grid), len(grid[0])
    cur = [0] * c
    cur[0] = grid[0][0]
    for i in xrange(1, c):
        cur[i] = cur[i-1] + grid[0][i]
    for i in xrange(1, r):
        cur[0] += grid[i][0]
        for j in xrange(1, c):
            cur[j] = min(cur[j-1], cur[j]) + grid[i][j]
    return cur[-1]

# change the grid itself
def minPathSum4(self, grid):
    if not grid:
        return
    r, c = len(grid), len(grid[0])
    for i in xrange(1, c):
        grid[0][i] += grid[0][i-1]
    for i in xrange(1, r):
        grid[i][0] += grid[i-1][0]
    for i in xrange(1, r):
        for j in xrange(1, c):
            grid[i][j] += min(grid[i-1][j], grid[i][j-1])
    return grid[-1][-1]

63. Unique Paths II

Follow up for “Unique Paths”:

Now consider if some obstacles are added to the grids. How many unique paths would there be?

An obstacle and empty space is marked as 1 and 0 respectively in the grid.

For example,

There is one obstacle in the middle of a 3x3 grid as illustrated below.

[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]

The total number of unique paths is 2.

Note: m and n will be at most 100.

def pathSum(self, root, sum):
    if not root:
        return []
    res = []
    self.dfs(root, sum, [], res)
    return res

def dfs(self, root, sum, ls, res):
    if not root.left and not root.right and sum == root.val:
        ls.append(root.val)
        res.append(ls)
    if root.left:
        self.dfs(root.left, sum-root.val, ls+[root.val], res)
    if root.right:
        self.dfs(root.right, sum-root.val, ls+[root.val], res)

def pathSum2(self, root, sum):
    if not root:
        return []
    if not root.left and not root.right and sum == root.val:
        return [[root.val]]
    tmp = self.pathSum(root.left, sum-root.val) + self.pathSum(root.right, sum-root.val)
    return [[root.val]+i for i in tmp]

# BFS + queue
def pathSum3(self, root, sum):
    if not root:
        return []
    res = []
    queue = [(root, root.val, [root.val])]
    while queue:
        curr, val, ls = queue.pop(0)
        if not curr.left and not curr.right and val == sum:
            res.append(ls)
        if curr.left:
            queue.append((curr.left, val+curr.left.val, ls+[curr.left.val]))
        if curr.right:
            queue.append((curr.right, val+curr.right.val, ls+[curr.right.val]))
    return res

# DFS + stack I
def pathSum4(self, root, sum):
    if not root:
        return []
    res = []
    stack = [(root, sum-root.val, [root.val])]
    while stack:
        curr, val, ls = stack.pop()
        if not curr.left and not curr.right and val == 0:
            res.append(ls)
        if curr.right:
            stack.append((curr.right, val-curr.right.val, ls+[curr.right.val]))
        if curr.left:
            stack.append((curr.left, val-curr.left.val, ls+[curr.left.val]))
    return res

# DFS + stack II
def pathSum5(self, root, s):
    if not root:
        return []
    res = []
    stack = [(root, [root.val])]
    while stack:
        curr, ls = stack.pop()
        if not curr.left and not curr.right and sum(ls) == s:
            res.append(ls)
        if curr.right:
            stack.append((curr.right, ls+[curr.right.val]))
        if curr.left:
            stack.append((curr.left, ls+[curr.left.val]))
    return res


A shorter version of previous code:

def pathSum1(self, root, sum):
    res = []
    self.dfs(root, sum, [], res)
    return res

def dfs(self, root, sum, path, res):
    if root:
        if sum == root.val and not root.left and not root.right:
            res.append(path+[root.val])
        self.dfs(root.left, sum-root.val, path+[root.val], res)
        self.dfs(root.right, sum-root.val, path+[root.val], res)

def pathSum2(self, root, sum):
    res, stack = [], [(root, sum, [])]
    while stack:
        node, sum, path = stack.pop()
        if node:
            if node.val == sum and not node.left and not node.right:
                res.append(path+[node.val])
            stack.append((node.right, sum-node.val, path+[node.val]))
            stack.append((node.left, sum-node.val, path+[node.val]))
    return res

def pathSum(self, root, sum):
    res, queue = [], collections.deque([(root, sum, [])])
    while queue:
        node, sum, path = queue.popleft()
        if node:
            if node.val == sum and not node.left and not node.right:
                res.append(path+[node.val])
                continue
            queue.append((node.left, sum-node.val, path+[node.val]))
            queue.append((node.right, sum-node.val, path+[node.val]))
    return res

62. Unique Paths

A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).

How many possible unique paths are there?

../../_images/robot_maze.png

Above is a 3 x 7 grid. How many possible unique paths are there?

Note: m and n will be at most 100.

# math C(m+n-2,n-1)
def uniquePaths1(self, m, n):
    if not m or not n:
        return 0
    return math.factorial(m+n-2)/(math.factorial(n-1) * math.factorial(m-1))

# O(m*n) space
def uniquePaths2(self, m, n):
    if not m or not n:
        return 0
    dp = [[1 for _ in xrange(n)] for _ in xrange(m)]
    for i in xrange(1, m):
        for j in xrange(1, n):
            dp[i][j] = dp[i-1][j] + dp[i][j-1]
    return dp[-1][-1]

# O(n) space
def uniquePaths(self, m, n):
    if not m or not n:
        return 0
    cur = [1] * n
    for i in xrange(1, m):
        for j in xrange(1, n):
            cur[j] += cur[j-1]
    return cur[-1]

# O(m*n) space
def uniquePathsWithObstacles1(self, obstacleGrid):
    if not obstacleGrid:
        return
    r, c = len(obstacleGrid), len(obstacleGrid[0])
    dp = [[0 for _ in xrange(c)] for _ in xrange(r)]
    dp[0][0] = 1 - obstacleGrid[0][0]
    for i in xrange(1, r):
        dp[i][0] = dp[i-1][0] * (1 - obstacleGrid[i][0])
    for i in xrange(1, c):
        dp[0][i] = dp[0][i-1] * (1 - obstacleGrid[0][i])
    for i in xrange(1, r):
        for j in xrange(1, c):
            dp[i][j] = (dp[i][j-1] + dp[i-1][j]) * (1 - obstacleGrid[i][j])
    return dp[-1][-1]

# O(n) space
def uniquePathsWithObstacles2(self, obstacleGrid):
    if not obstacleGrid:
        return
    r, c = len(obstacleGrid), len(obstacleGrid[0])
    cur = [0] * c
    cur[0] = 1 - obstacleGrid[0][0]
    for i in xrange(1, c):
        cur[i] = cur[i-1] * (1 - obstacleGrid[0][i])
    for i in xrange(1, r):
        cur[0] *= (1 - obstacleGrid[i][0])
        for j in xrange(1, c):
            cur[j] = (cur[j-1] + cur[j]) * (1 - obstacleGrid[i][j])
    return cur[-1]

# in place
def uniquePathsWithObstacles(self, obstacleGrid):
    if not obstacleGrid:
        return
    r, c = len(obstacleGrid), len(obstacleGrid[0])
    obstacleGrid[0][0] = 1 - obstacleGrid[0][0]
    for i in xrange(1, r):
        obstacleGrid[i][0] = obstacleGrid[i-1][0] * (1 - obstacleGrid[i][0])
    for i in xrange(1, c):
        obstacleGrid[0][i] = obstacleGrid[0][i-1] * (1 - obstacleGrid[0][i])
    for i in xrange(1, r):
        for j in xrange(1, c):
            obstacleGrid[i][j] = (obstacleGrid[i-1][j] + obstacleGrid[i][j-1]) * (1 - obstacleGrid[i][j])
    return obstacleGrid[-1][-1]

59. Spiral Matrix II

Given an integer n, generate a square matrix filled with elements from 1 to n的2次方 in spiral order.

For example, Given n = 3, You should return the following matrix:

[
 [ 1, 2, 3 ],
 [ 8, 9, 4 ],
 [ 7, 6, 5 ]
]
def generateMatrix(self, n):
    if not n:
        return []
    res = [[0 for _ in xrange(n)] for _ in xrange(n)]
    left, right, top, down, num = 0, n-1, 0, n-1, 1
    while left <= right and top <= down:
        for i in xrange(left, right+1):
            res[top][i] = num
            num += 1
        top += 1
        for i in xrange(top, down+1):
            res[i][right] = num
            num += 1
        right -= 1
        for i in xrange(right, left-1, -1):
            res[down][i] = num
            num += 1
        down -= 1
        for i in xrange(down, top-1, -1):
            res[i][left] = num
            num += 1
        left += 1
    return res

56. Merge Intervals

Given a collection of intervals, merge all overlapping intervals.

For example

Given [1,3],[2,6],[8,10],[15,18],
return [1,6],[8,10],[15,18].

55. Jump Game

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position.

Determine if you are able to reach the last index.

For example:

::

A = [2,3,1,1,4], return true.

A = [3,2,1,0,4], return false.

# DP (like Word Break I) LTE
def canJump1(self, nums):
    dp = [True] * len(nums)
    for i in xrange(1, len(nums)):
        for j in xrange(i):
            dp[i] = dp[j] and nums[j] >= i-j
    return dp[-1]

def canJump2(self, nums):
    maxReach = 0
    for i in xrange(len(nums)):
        if i > maxReach:
            return False
        maxReach = max(maxReach, i+nums[i])
    return True

def canJump3(self, nums):
    remain = 0
    for i in xrange(len(nums)):
        remain = max(remain-1, nums[i])
        if remain == 0 and i < len(nums)-1:
            return False
    return True

def canJump(self, nums):
    maxReach = 0
    i = 0
    while i < len(nums) and i <= maxReach:
        maxReach = max(maxReach, i+nums[i])
        i += 1
    return i == len(nums)

54. Spiral Matrix

Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.

For example, Given the following matrix:

[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]

You should return [1,2,3,6,9,8,7,4,5].

def spiralOrder(self, matrix):
    res = []
    while matrix:
        res.extend(matrix.pop(0)) # left to right
        if matrix and matrix[0]: # top to dwon
            for row in matrix:
                res.append(row.pop())
        if matrix: # right to left
            res.extend(matrix.pop()[::-1])
        if matrix and matrix[0]: # bottom to up
            for row in matrix[::-1]:
                res.append(row.pop(0))
    return res


def spiralOrder(self, matrix):
    if not matrix:
        return []
    left, right, top, down, res = 0, len(matrix[0])-1, 0, len(matrix)-1, []
    while left <= right and top <= down:
        res.extend(matrix[top][left:right+1]) # left to right
        top += 1
        for i in xrange(top, down+1): # top to down
            res.append(matrix[i][right])
        right -= 1
        if top <= down:
            res.extend(matrix[down][left:right+1][::-1]) # right to left
            down -= 1
        if left <= right:
            for i in xrange(down, top-1, -1): # bottom to up
                res.append(matrix[i][left])
            left += 1
    return res

48. Rotate Image

You are given an n x n 2D matrix representing an image.

Rotate the image by 90 degrees (clockwise).

Follow up: Could you do this in-place?