leetcode
本题的核心目标是捕获矩阵中所有被 'X' 围绕的 'O' 区域并将其替换为 'X'。我们可以采用逆向思维,因为位于矩阵边缘的 'O' 及其相连的 'O' 区域不会被围绕,所以我们先找出这些不会被围绕的 'O' 区域,将其标记为其他字符(如 '#'),然后遍历整个矩阵,把剩下的 'O' 替换为 'X',最后再把标记为 '#' 的字符还原为 'O'。
- 边界检查:首先检查矩阵是否为空或者行数、列数小于等于 2,如果是则直接返回,因为这种情况下不存在被围绕的区域。
- 标记边缘 'O' 及其相连区域:
- 遍历矩阵的上下边界,对于边界上的 'O',使用深度优先搜索(DFS)或广度优先搜索(BFS)将其相连的 'O' 区域标记为 '#'。
- 遍历矩阵的左右边界,同样对边界上的 'O' 及其相连区域进行标记。
- 替换剩余 'O' 为 'X':再次遍历整个矩阵,将所有未被标记的 'O' 替换为 'X'。
- 还原标记的 '#' 为 'O':最后将所有标记为 '#' 的字符还原为 'O'。
package main
import "fmt"
// solve 函数用于捕获被围绕的区域
func solve(board [][]byte) {
if len(board) == 0 || len(board[0]) == 0 {
return
}
m, n := len(board), len(board[0])
// 标记边缘 'O' 及其相连区域
for i := 0; i < m; i++ {
dfs(board, i, 0)
dfs(board, i, n-1)
}
for j := 0; j < n; j++ {
dfs(board, 0, j)
dfs(board, m-1, j)
}
// 替换剩余 'O' 为 'X',还原 '#' 为 'O'
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
if board[i][j] == 'O' {
board[i][j] = 'X'
} else if board[i][j] == '#' {
board[i][j] = 'O'
}
}
}
}
// dfs 函数用于深度优先搜索标记相连的 'O' 区域
func dfs(board [][]byte, i, j int) {
m, n := len(board), len(board[0])
if i < 0 || i >= m || j < 0 || j >= n || board[i][j] != 'O' {
return
}
board[i][j] = '#'
dfs(board, i+1, j)
dfs(board, i-1, j)
dfs(board, i, j+1)
dfs(board, i, j-1)
}
- 时间复杂度:\(O(m \times n)\),其中 m 是矩阵的行数,n 是矩阵的列数。我们需要遍历矩阵三次,每次遍历的时间复杂度都是 \(O(m \times n)\)。
- 空间复杂度:\(O(m \times n)\),主要是递归调用栈的空间开销。在最坏情况下,整个矩阵都是 'O',递归深度可能达到 \(m \times n\)。
对于输入 board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]]:
- 标记边缘 'O' 及其相连区域:
- 矩阵的上下左右边界中,第四行第二列的 'O' 位于边缘,从该 'O' 开始进行深度优先搜索,将其相连的 'O' 标记为 '#'。此时矩阵变为:
[["X","X","X","X"],
["X","O","O","X"],
["X","X","O","X"],
["X","#","X","X"]]
- 替换剩余 'O' 为 'X':将未被标记的 'O' 替换为 'X',矩阵变为:
[["X","X","X","X"],
["X","X","X","X"],
["X","X","X","X"],
["X","#","X","X"]]
- 还原标记的 '#' 为 'O':将标记为 '#' 的字符还原为 'O',最终矩阵变为:
[["X","X","X","X"],
["X","X","X","X"],
["X","X","X","X"],
["X","O","X","X"]]
func main() {
board := [][]byte{
{'X', 'X', 'X', 'X'},
{'X', 'O', 'O', 'X'},
{'X', 'X', 'O', 'X'},
{'X', 'O', 'X', 'X'},
}
solve(board)
for _, row := range board {
fmt.Println(string(row))
}
}