LeetCode算法题10:DFS/BFS-扫雷游戏
文章目錄
- 前言
- 一、掃雷游戲
- DFS :
- BFS
- 二、被圍繞的區域
- DFS 1:
- DFS 2:
- 總結
前言
??????DFS 和 BFS,可參考之前的一篇文章:https://blog.csdn.net/Little_ant_/article/details/123415889?spm=1001.2014.3001.5501 介紹了二者的偽代碼實現和關于 BFS 實現時需要注意的地方。
??????掃雷游戲和被圍繞的區域均為不太簡單的DFS/BFS,即當前元素狀態依賴于下一步(周圍)的元素值。
一、掃雷游戲
??????題目鏈接:https://leetcode-cn.com/problems/minesweeper/
??????題目描述:
讓我們一起來玩掃雷游戲!
給你一個大小為 m x n 二維字符矩陣 board ,表示掃雷游戲的盤面,其中:
‘M’ 代表一個 未挖出的 地雷,
‘E’ 代表一個 未挖出的 空方塊,
‘B’ 代表沒有相鄰(上,下,左,右,和所有4個對角線)地雷的 已挖出的 空白方塊,
數字(‘1’ 到 ‘8’)表示有多少地雷與這塊 已挖出的 方塊相鄰,
‘X’ 則表示一個 已挖出的 地雷。
給你一個整數數組 click ,其中 click = [clickr, clickc] 表示在所有 未挖出的 方塊(‘M’ 或者 ‘E’)中的下一個點擊位置(clickr 是行下標,clickc 是列下標)。
根據以下規則,返回相應位置被點擊后對應的盤面:
如果一個地雷(‘M’)被挖出,游戲就結束了- 把它改為 ‘X’ 。
如果一個 沒有相鄰地雷 的空方塊(‘E’)被挖出,修改它為(‘B’),并且所有和其相鄰的 未挖出 方塊都應該被遞歸地揭露。
如果一個 至少與一個地雷相鄰 的空方塊(‘E’)被挖出,修改它為數字(‘1’ 到 ‘8’ ),表示相鄰地雷的數量。
如果在此次點擊中,若無更多方塊可被揭露,則返回盤面。
DFS :
??????思路為:1,如果當前位置元素為’M’,修改其為’X‘并返回;如果為’E’的話,**這里注意和簡單的 DFS 有點差異,區別在于簡單的 DFS 這時便可以對當前位置元素做訪問或修改,但是本題中需要首先判斷當前位置周圍 8 個元素的狀態,然后根據結果來對當前位置進行修改。**2,根據題意,DFS 遞歸的情況僅針對于當前位置為’B’的情況,相對的是如果當前位置為數字的話,不需要進行遞歸了。參考代碼如下:
int[] xi={1,0,0,-1,1,1,-1,-1};int[] yi={0,1,-1,0,-1,1,-1,1};public char[][] updateBoard(char[][] board, int[] click) {int x=click[0],y=click[1];if(board[x][y]=='M'){board[x][y]='X';return board;}solve(board,x,y);return board;}public void solve(char[][] board,int x,int y){//和一般 DFS 不一樣的是:當前位置的判斷依賴于其周圍位置元素的狀態int count=0;for(int i=0;i<8;i++){int newX=x+xi[i],newY=y+yi[i];if(newX<0||newY<0||newX>=board.length||newY>=board[0].length)continue;if(board[newX][newY]=='M')count++;}if(count!=0)board[x][y]=(char)('0'+count);else{board[x][y]='B';for(int i=0;i<8;i++){int newX=x+xi[i],newY=y+yi[i];if(newX<0||newY<0||newX>=board.length||newY>=board[0].length)continue;if(board[newX][newY]=='E')//這里注意僅對未翻開的格子進行遞歸判斷。solve(board,newX,newY);}}}BFS
?????? BFS 中,為了避免相同元素重復入隊有兩種解決方法:1,在入隊時修改其值,2,采用標記數組。本題沒法在入隊時修改其值,所以采用標記數組的方法(在入隊時標記)。此問題在博客https://blog.csdn.net/Little_ant_/article/details/123415889?spm=1001.2014.3001.5501有提到過。參考代碼如下:
public char[][] updateBoard(char[][] board, int[] click) {int[] xi={1,0,0,-1,1,1,-1,-1};int[] yi={0,1,-1,0,-1,1,-1,1};int x=click[0],y=click[1];LinkedList<int[]> queue=new LinkedList<>();queue.add(new int[]{x,y});if(board[x][y]=='M'){queue.remove();board[x][y]='X';}int count;boolean[][] flag=new boolean[board.length][board[0].length];flag[x][y]=true;while(!queue.isEmpty()){int[] tmp=queue.poll();x=tmp[0];y=tmp[1];count=0;for(int i=0;i<8;i++){int newX=x+xi[i],newY=y+yi[i];if(newX<0||newY<0||newX>=board.length||newY>=board[0].length)continue;if(board[newX][newY]=='M')count++;}if(count!=0)board[x][y]=(char)('0'+count);else{board[x][y]='B';for(int i=0;i<8;i++){int newX=x+xi[i],newY=y+yi[i];if(newX<0||newY<0||newX>=board.length||newY>=board[0].length||flag[newX][newY])continue;if(board[newX][newY]=='E'){queue.add(new int[]{newX,newY});//沒法在入隊時更改其值,因為現在還不確定其狀態。flag[newX][newY]=true;}}}}return board;}二、被圍繞的區域
??????題目鏈接:https://leetcode-cn.com/problems/surrounded-regions/
??????題目描述:給你一個 m x n 的矩陣 board ,由若干字符 ‘X’ 和 ‘O’ ,找到所有被 ‘X’ 圍繞的區域,并將這些區域里所有的 ‘O’ 用 ‘X’ 填充。
DFS 1:
??????思路為:依次對每一整塊‘O’區域判斷,如果這一整塊區域被’X’所圍繞,將它們全部置為‘X’;如果這塊區域中有’O’在邊界上,那么此區域跳過,繼續對下一塊區域判斷。
??????由于給定一個‘O’,沒法在當前就得到它是否要被變為’X’,所以將這一整塊區域上’O’的位置全部保存下來,然后在DFS遍歷中判斷是否有’O’在邊界上。參考代碼如下:
int[] addi={1,-1,0,0};int[] addj={0,0,1,-1};Queue<int[]> cache=new LinkedList<>();//用來保存某一塊'O'區域的位置boolean flag;//為 true 時表示當前區域中有'O'在邊界上public void solve(char[][] board) {int m=board.length,n=board[0].length;boolean[][] visited=new boolean[m][n];for(int i=0;i<m;i++)for(int j=0;j<n;j++){if(board[i][j]=='O'&&visited[i][j]==false){flag=false;dealSurround(board,i,j,visited);if(flag)cache.clear();//有'O'存在邊界上,跳過else{int[] tmp;//被'X'包圍時,全部變為'X'while(!cache.isEmpty()){tmp=cache.poll();board[tmp[0]][tmp[1]]='X';}}} }}void dealSurround(char[][] board,int i,int j,boolean[][] visited){//不管flag最終返回 true 或 false,必須將一整塊 'O' 訪問完。visited[i][j]=true;cache.add(new int[]{i,j});for(int k=0;k<4;k++){int newX=i+addi[k],newY=j+addj[k];if(newX<0||newY<0||newX>=board.length||newY>=board[0].length){//表示(i,j)處的'O'在邊界上。flag=true;continue;}if(visited[newX][newY]==false&&board[newX][newY]=='O')dealSurround(board,newX,newY,visited);}}DFS 2:
??????更簡單的想法:從邊界上的’O’開始判斷,進行DFS遍歷,標記這些’O’塊;然后對整個數組中未標記的’O’全部置為’X’。參考代碼如下:
boolean[][] visited;int[] addi={1,-1,0,0};int[] addj={0,0,1,-1};public void solve(char[][] board) {int m=board.length,n=board[0].length;visited=new boolean[m][n];for(int i=0;i<n;i++){if(board[0][i]=='O')setVisited(board,0,i);if(board[m-1][i]=='O')setVisited(board,m-1,i);}for(int i=0;i<m;i++){if(board[i][0]=='O')setVisited(board,i,0);if(board[i][n-1]=='O')setVisited(board,i,n-1);}for(int i=0;i<m;i++)for(int j=0;j<n;j++){if(board[i][j]=='O'&&visited[i][j]==false)board[i][j]='X';}}void setVisited(char[][] board,int i,int j){visited[i][j]=true;for(int k=0;k<4;k++){int newX=i+addi[k],newY=j+addj[k];if(newX<0||newY<0||newX>=board.length||newY>=board[0].length||board[newX][newY]=='X'||visited[newX][newY]==true)continue;setVisited(board,newX,newY);}}總結
??????完
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的LeetCode算法题10:DFS/BFS-扫雷游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode算法题9:递归和回溯-N
- 下一篇: LeetCode算法题11:递归和回溯-