问题描述
给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。
示例
输入:
[
[1,1,1],
[1,0,1],
[1,1,1]
]
输出:
[
[1,0,1],
[0,0,0],
[1,0,1]
]
输入:
[
[0,1,2,0],
[3,4,5,2],
[1,3,1,5]
]
输出:
[
[0,0,0,0],
[0,4,5,0],
[0,3,1,0]
]
题目分析
汗,这题我一开始把原地算法想成了是原地修改。然后想当然的用了2个set记录要变0的行和列,然后让他们变0.
其实人家说的原地算法是利用O(1)的空间复杂度。
我们在思考过程中发现,如果你想用扩展的方式来搞定的话,要解决以下问题:
- 扩展了行和列之后,你在下次遍历的时候就不清楚这个位置到底是原本就是0,还是被你修改过后是0了。
诚然,对于Python这种语言,你完全可以将初始值为0的值置为False,这样的话我们只需要判断是不是False就可以了。但是对于Java等类型严格的语言来说这题就不可解了吗?不是的。
我们发现这题就是个映射的思想。我们发现某个元素matrix[i][j]为0时,那代表了我们需要把matrix[i][…],和matrix[…][j] 全部置为0.所以我们可以把这个为0的特征映射到matrix[i][0] 和matrix[0][j]上。这样的话我们就可以根据第一行第一列的状态进行初始化了。
我们利用第一行第一列的状态时,我们并不能同时对第一行或者第一列进行置0操作。因为那样的话就违背了我们的初衷:我们没有解决上面提到的问题。所以我们可以对除第一行第一列之外的元素进行置0操作,弄完了之后再说第一行第一列的事儿。
第一行第一列比较特殊的。因为我们是把其他元素的特征存储在了第一行,所以我们要在存储之前搞明白到底要怎么对第一行第一列进行操作。
我们需要两个flag标记一下到底在第一行/第一列有没有遇到0,以便最后进行处理。
AC代码:
class Solution:
def setZeroes(self, matrix) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
if len(matrix) == 0:
return
flagI = flagJ = False
for j in range(len(matrix[0])):
if matrix[0][j] == 0:
flagJ = True
for i in range(len(matrix)):
if matrix[i][0] == 0:
flagI = True
for j in range(len(matrix[0])):
if matrix[i][j] == 0:
matrix[i][0] = matrix[0][j] = 0
for i in range(1,len(matrix)):
for j in range(1,len(matrix[0])):
if matrix[i][0] == 0 or matrix[0][j] == 0:
matrix[i][j] = 0
if flagI:
for i in range(len(matrix)):
matrix[i][0] = 0
if flagJ:
for j in range(len(matrix[0])):
matrix[0][j] = 0
print(matrix)
s = Solution()
s.setZeroes([[0,1,2,0],[3,4,5,2],[1,3,1,5]])