73. Set Matrix Zeroes
MediumDescription
給定一個 m x n 的矩陣,如果某個元素為 0,則將其所在的整行和整列都設為 0。要求原地操作。
Example:
Input: matrix = [[1,1,1],[1,0,1],[1,1,1]] Output: [[1,0,1],[0,0,0],[1,0,1]]
Intuition#
核心思路:用矩陣的第一行和第一列作為標記,記錄哪些行列需要歸零,達到 O(1) 額外空間。
- 不能邊遍歷邊歸零,否則新產生的 0 會造成連鎖反應
- 需要先記錄哪些行列有 0,再統一歸零
- 用額外的 Set 記錄需要 O(m + n) 空間;用矩陣自身的第一行/列當標記只需 O(1)
Approaches#
1: 用 Set 記錄#
- 概念: 先遍歷矩陣找出所有 0 的行列,存入兩個 Set,再遍歷矩陣歸零
- 時間複雜度:
O(m * n)- 遍歷矩陣兩次 - 空間複雜度:
O(m + n)- 兩個 Set 記錄行列
class Solution {
fun setZeroes(matrix: Array<IntArray>) {
val rows = HashSet<Int>()
val cols = HashSet<Int>()
val m = matrix.size
val n = matrix[0].size
for (i in 0 until m) {
for (j in 0 until n) {
if (matrix[i][j] == 0) {
rows.add(i)
cols.add(j)
}
}
}
for (i in 0 until m) {
for (j in 0 until n) {
if (i in rows || j in cols) {
matrix[i][j] = 0
}
}
}
}
}⭐2: 用第一行/列當標記#
- 概念: 用第一行和第一列記錄該列/行是否需要歸零,額外用一個變數記錄第一列本身是否需要歸零
- 時間複雜度:
O(m * n)- 遍歷矩陣兩次 - 空間複雜度:
O(1)- 只用一個額外變數
class Solution {
fun setZeroes(matrix: Array<IntArray>) {
val m = matrix.size
val n = matrix[0].size
var firstColZero = false
for (i in 0 until m) {
if (matrix[i][0] == 0) firstColZero = true
for (j in 1 until n) {
if (matrix[i][j] == 0) {
matrix[i][0] = 0
matrix[0][j] = 0
}
}
}
// 從下往上歸零(避免先改到第一行/列的標記)
for (i in m - 1 downTo 0) {
for (j in n - 1 downTo 1) {
if (matrix[i][0] == 0 || matrix[0][j] == 0) {
matrix[i][j] = 0
}
}
if (firstColZero) matrix[i][0] = 0
}
}
}歸零時必須從最後一行開始往上處理,因為第一行的標記值在處理其他行時還需要使用。如果先處理第一行,標記會被破壞。
🔑 Takeaways#
- Pattern: 利用矩陣自身空間做標記是常見的 O(1) 空間優化技巧
- 關鍵技巧: 用第一行/列當標記時,處理順序很重要——必須最後才處理用來當標記的那行/列