题目来源于leetcode,解法和思路仅代表个人观点。传送门。
难度:中等
用时:00:10:00 (看了示例的解释之后,豁然开朗啊)
题目
给定一个二维的矩阵,包含 ‘X’ 和 ‘O’(字母 O)。
找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。
示例:
X X X X
X O O X
X X O X
X O X X
运行你的函数后,矩阵变为:
X X X X
X X X X
X X X X
X O X X
解释:
被围绕的区间不会存在于边界上,换句话说,任何边界上的 ‘O’ 都不会被填充为 ‘X’。 任何不在边界上,或不与边界上的 ‘O’ 相连的’O’ 最终都会被填充为 ‘X’。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
思路
题目已经给出了很明显的提示:
(1)任何边界上的 ‘O’ 都不会被填充为 ‘X’。
(2)任何不在边界上,或不与边界上的 ‘O’ 相连的‘O’ 最终都会被填充为 ‘X’。
那么我们的思路就是这样的:
- 取出所有边界上的’O’。
- 对边界上的’O’进行深度遍历(广度遍历),标记边界上的’O’和与边界上的’O’相连的’O’。
- 对没有标记的矩阵上的(内)点,全部置为’X’。
代码
class Solution {
/*
1.取出所有边界上的'O'
2.对边界上的'O'进行深度遍历(广度遍历),标记边界上的'O'和与边界上的'O'相连的'O'
3.对没有标记的矩阵上的点,全部置为'X'
*/
//记录矩阵,-1表示边界上的点,1表示不被填充的'O'
int[][] flag;
public void solve(char[][] board) {
//特殊情况,这里被坑了(我觉得leetcode应该不会传一个null过来)
if(board == null || board.length == 0){
return;
}
flag = new int[board.length][board[0].length];
//1.取出边界上的'O'
for(int i=0;i<board.length;i++){
for(int j=0;j<board[0].length;j++){
//如果在边界
if(i==0 || j==0 || i==board.length-1 || j==board[0].length-1){
//如果是'O'
if(board[i][j] == 'O'){
flag[i][j] = -1;
}
}
}
}
//对边界上的'O'进行深度遍历。
for(int i=0;i<flag.length;i++){
for(int j=0;j<flag[0].length;j++){
//如果在边界
if(i==0 || j==0 || i==board.length-1 || j==board[0].length-1){
//如果flag == -1。
//为什么要置为-1,因为dfs遍历的时候,flag==1需要作为不重复遍历'O'的【边界条件】
int[][] record = new int[board.length][board[0].length];
if(flag[i][j] == -1){
dfs(i,j,record,board);
}
}
}
}
//对内部的点
for(int i=1;i<board.length-1;i++){
for(int j=1;j<board[0].length-1;j++){
//没有被记录的点全部置为'X'
if(flag[i][j] == 0){
board[i][j] = 'X';
}
}
}
return;
}
//record记录,该点是否被遍历。
public void dfs(int i,int j,int[][] record,char[][] board){
//这里要把【数组】的判断条件放在后面,否则会出现【越界】错误。
// ‘||’ 是从左到右开始判断的
if(i<0 || j<0 || i>=board.length || j >= board[0].length || record[i][j] == 1 || flag[i][j] == 1){
return;
}
if(board[i][j] == 'O'){
flag[i][j] = 1;
//上下左右遍历
record[i][j] = 1;
dfs(i-1,j,record,board);
dfs(i+1,j,record,board);
dfs(i,j-1,record,board);
dfs(i,j+1,record,board);
record[i][j] = 0;
}
return;
}
}
算法复杂度
时间复杂度: O(n*m)。需要O(n*m)记录边上的点(最少也需要O(2*(n+m))。对于边界上的点,深度遍历dfs最差需要O(n*m)。把标记的部分置为‘X’,需要O(n*m)。
空间复杂度: O(n*m)。标记的flag数组和深度遍历的record临时数组。