LeetCode day18
Diffculty: Medium
62. Unique Paths
Topic: Array, DP
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?
Above is a 7 x 3 grid. How many possible unique paths are there?
Example 1:
Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Right -> Down
2. Right -> Down -> Right
3. Down -> Right -> Right
Example 2:
Input: m = 7, n = 3
Output: 28
Constraints:
- 1 <= m, n <= 100
- It’s guaranteed that the answer will be less than or equal to 2 * 10 ^ 9.
Approach1
动态规划5大步骤:
- 定义状态:即定义数据元素的含义,这里定义dp[i][j]为当前位置的路径数,i表示i列,j表示j行
- 建立状态转移方程:因为从题目要求中可以看出,机器人只能向右或向下移动. 所以到达dp[i][j]就可能是经过dp[i-1][j]到达,也可能是经过dp[i][j-1]到达(列减一或者行减一). 所以状态转移方程为:dp[i][j]=dp[i-1][j]+dp[i][j-1]
- 设定初始值:通过状态转移方程可以看出,i和j下表要从1开始,否则会导致数组溢出异常(因为减一). 同时每一个位置点代表到达当前位置的路径条数,所以要设置最初的路径条数即dp[i][0]=1,dp[0][j]=1,即第一行,第一列值为1.
- 状态压缩:即优化数组空间,每次状态的更新只依赖于前一次的状态,优化一般作用于多维数组,观察是否可以将多维数组以一维数组来动态表示,即用一维数组来保存上次的状态. 这道题的优化方法是存在的. 具体看下面的代码解释. 状态转移方程:dp[i] = dp[i-1] + dp[i]
选出结果:根据状态转移方程,求路径的总数,因此dp[-1][-1]表示的是到达最后位置的路径总条数
def uniquePaths(m, n): """ :type m: int :type n: int :rtype: int """ # 采用二位数组形式的动态规划 # f[i][j]表示当前移动到的总次数,要求f[-1][-1] # 状态转移公式:f[i][j] = f[i-1][j]+f[i][j-1] # 初始值:每一步移动的次数可以看做横轴和纵轴的和,因此 f[i][0] = 1,f[0][j]=1 # 运动的轨迹:要么往下,要么往左 # 时间复杂度:O(m*n),空间复杂度:O(m*n) f = [[0 for i in range(n)] for i in range(m)] for i in range(m): f[i][0] = 1 for j in range(n): f[0][j] = 1 for i in range(1,m): for j in range(1,n): f[i][j] = f[i-1][j]+f[i][j-1] return f[-1][-1] """优化空间复杂度为O(n)""" # 对二维矩阵进行压缩成一位数组,将最新生成的值覆盖掉旧的值,逐行求解当前位置的最新路径条数! # 实质:在于动态计算并替换当前位置下的路径数最新值 # 状态转移公式变成:f[i] = f[i-1]+f[i] # 初始值: f = [1]*m,取横轴 # f[-1]表示可能路径的总数 # 空间复杂度:O(n),时间复杂度:O(m*n) f = [1]*m for j in range(1,n): for i in range(1,m): f[i] = f[i-1]+f[i] return f[-1]
73. Set Matrix Zeroes
Topic: Array
Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in-place.
Example 1:
Input:
[
[1,1,1],
[1,0,1],
[1,1,1]
]
Output:
[
[1,0,1],
[0,0,0],
[1,0,1]
]
Example 2:
Input:
[
[0,1,2,0],
[3,4,5,2],
[1,3,1,5]
]
Output:
[
[0,0,0,0],
[0,4,5,0],
[0,3,1,0]
]
Follow up:
- 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?
Approach1
用 O(m+n)额外空间, 两遍扫matrix,第一遍用集合记录哪些行,哪些列有0;第二遍置0
def setZeroes(matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
row = len(matrix)
col = len(matrix[0])
row_zero = set()
col_zero = set()
for i in range(row):
for j in range(col):
if matrix[i][j] == 0:
row_zero.add(i)
col_zero.add(j)
for i in range(row):
for j in range(col):
if i in row_zero or j in col_zero:
matrix[i][j] = 0
Approach2
用O(1)空间, 用matrix第一行和第一列记录该行该列是否有0,作为标志位.
但是对于第一行,和第一列要设置一个标志位,为了防止自己这一行(一列)也有0的情况
def setZeroes(matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
row = len(matrix)
col = len(matrix[0])
row0_flag = False
col0_flag = False
# 找第一行是否有0
for j in range(col):
if matrix[0][j] == 0:
row0_flag = True
break
# 第一列是否有0
for i in range(row):
if matrix[i][0] == 0:
col0_flag = True
break
# 把第一行或者第一列作为 标志位
for i in range(1, row):
for j in range(1, col):
if matrix[i][j] == 0:
matrix[i][0] = matrix[0][j] = 0
#print(matrix)
# 置0
for i in range(1, row):
for j in range(1, col):
if matrix[i][0] == 0 or matrix[0][j] == 0:
matrix[i][j] = 0
if row0_flag:
for j in range(col):
matrix[0][j] = 0
if col0_flag:
for i in range(row):
matrix[i][0] = 0
# 简化版===========================================
"""
Do not return anything, modify matrix in-place instead.
"""
flag_col = False
row = len(matrix)
col = len(matrix[0])
for i in range(row): # 用matrix第一行和第一列记录该行该列是否有0,作为标志位
if matrix[i][0] == 0: flag_col = True
for j in range(1,col):
if matrix[i][j] == 0:
matrix[i][0] = matrix[0][j] = 0
# 如果标志位为0, 则该行(列)设为0
for i in range(row - 1, -1, -1): # from row-1 to 0
for j in range(col - 1, 0, -1): # from col-1 to 1
if matrix[i][0] == 0 or matrix[0][j] == 0:
matrix[i][j] = 0
if flag_col == True: matrix[i][0] = 0
75. Sort Colors
Topic: Array, Sort, Two pointer
Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue.
Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.
Note: You are not suppose to use the library’s sort function for this problem.
Example:
Input: [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]
Follow up:
- A rather straight forward solution is a two-pass algorithm using counting sort.
- First, iterate the array counting number of 0’s, 1’s, and 2’s, then overwrite array with total number of 0’s, then 1’s and followed by 2’s.
- Could you come up with a one-pass algorithm using only constant space?
这道题目就是要给只有 0, 1, 2 三种数字的数组排序.
使用快速排序
python的builtin function - sort(), 是in-place的
Approach1
一次遍历,三指针.
l 指向 0 的右边,r 指向 2 的最左边,cur 则是当前查看的数字。
如果当前的数字是 0,就交换给 l,如果是 2 则交换给 r。如果是 1 就不用动了。
但是这里和 l 交换与和 r 交换不同的是,与 l 交换后 cur 加一以跳过刚从前面换过来的数组,但是与 r 交换不行,这是因为与 l 交换来的数,都是前面过来的,一定是 1,所以不用再看.
def sortColors(nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
l = cur = 0
r = len(nums) - 1
while cur <= r:
if nums[cur] == 0:
if cur != l:
nums[cur], nums[l] = nums[l], nums[cur]
cur += 1
l += 1
elif nums[cur] == 2:
nums[cur], nums[r] = nums[r], nums[cur]
r -= 1
else:
cur += 1
时间复杂度:O(log(n))
空间复杂度:O(1)
Approach2
两次遍历,统计个数 + 生成新数字
两次遍历的方法比较简单,第一次遍历先统计出每个数字出现的次数,下一次遍历直接按照次数生成新数字就可以了,完全不用交换数字
def sortColors(nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
cnt = [0] * 3
for n in nums:
cnt[n] += 1
i = 0
for cur in range(3):
for j in range(cnt[cur]):
nums[i] = cur
i += 1