dfs求解的思路:
首先是確定開始的狀態集合,也就是一個起點還是多個起點。
其次,是搜索的集合,有多少種狀態可以到達。比如上下左右是四種。
最後就是按照題目要求返回求解的內容,常見的就是求連通圖的個數。
Leetcode980:不同路徑III
在二維網格 grid 上,有 4 種類型的方格:
1 表示起始方格。且只有一個起始方格。
2 表示結束方格,且只有一個結束方格。
0 表示我們可以走過的空方格。
-1 表示我們無法跨越的障礙。
返回在四個方向(上、下、左、右)上行走時,從起始方格到結束方格的不同路徑的數目,每一個無障礙方格都要通過一次。
示例 1:
輸入:[[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
輸出:2
解釋:我們有以下兩條路徑:
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2)
2. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2)
示例 2:輸入:[[1,0,0,0],[0,0,0,0],[0,0,0,2]]
輸出:4
解釋:我們有以下四條路徑:
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2),(2,3)
2. (0,0),(0,1),(1,1),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,3),(1,3),(2,3)
3. (0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(1,1),(0,1),(0,2),(0,3),(1,3),(2,3)
4. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2),(2,3)
示例 3:輸入:[[0,1],[2,0]]
輸出:0
解釋:
沒有一條路能完全穿過每一個空的方格一次。
請注意,起始和結束方格可以位於網格中的任意位置。
提示:
1 <= grid.length * grid[0].length <= 20
這個問題就是路徑的搜索,起點唯一,從起點出發,可以搜索的是上下左右,最後是判斷結果是否滿足要求:對於這個問題來說,滿足要求代表着所有可以到達的地方都經過了,也就是blank爲0,並且正好抵達終點。在搜索的過程中,需要更新blank的個數。這裏,有一點是之前dfs一直都是沒有返回值的,但是這個問題返回int,對路徑進行計數。
class Solution {
public:
int dfs(vector<vector<int>>& grid,int x, int y,int blank,int n,int m)
{
if(x<0||x>=n||y>=m||y<0||grid[x][y]==-1)
return 0;
if(grid[x][y]==2)//到達終點
return 0==blank?1:0;//如果空格都走完了 那麼就是合格的
//否則標記爲障礙 表示走過了
grid[x][y]=-1;
int fix=0;
fix+=dfs(grid,x-1,y,blank-1,n,m);
fix+=dfs(grid,x+1,y,blank-1,n,m);
fix+=dfs(grid,x,y+1,blank-1,n,m);
fix+=dfs(grid,x,y-1,blank-1,n,m);
grid[x][y]=0;//到達目標 狀態清0
return fix;
}
int uniquePathsIII(vector<vector<int>>& grid) {
//dp[i][j]:到終點(i,j)的下標路徑
//正常情況:dp[i][j]=dp[i-1][j]+dp[i+1][j]+dp[i][j-1]+dp[i][j+1]
int n=grid.size();
int m=grid[0].size();
int start_i=0,start_j=0;
int blank=0;//統計空格 每一次遍歷都需要將所有的空格走過一次
for(int i=0;i<n;++i)
{
for(int j=0;j<m;++j)
{
if(grid[i][j]==1)
{
start_i=i;
start_j=j;
++blank;
}
else if(grid[i][j]==0)
{
++blank;
}
}
}
return dfs(grid,start_i,start_j,blank,n,m);
}
};
Leetcode130.被圍繞的區域
給定一個二維的矩陣,包含 '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'。如果兩個元素在水平或垂直方向相鄰,則稱它們是“相連”的。
這道題,也是用dfs進行遍歷,但是需要注意的就是我們處理邊緣的‘O’,找到所有沒有被包圍的‘O’。剩下的‘O’就是被包圍的。
class Solution {
public:
void dfs(vector<vector<char>>&board,int x,int y,int n,int m)
{
if(x<0||x>=n||y<0||y>=m||board[x][y]=='X')
return;
if(board[x][y]=='O')
{
board[x][y]='A';
dfs(board,x-1,y,n,m);
dfs(board,x+1,y,n,m);
dfs(board,x,y+1,n,m);
dfs(board,x,y-1,n,m);
}
}
void solve(vector<vector<char>>& board) {
//遍歷邊界上的字符
int n=board.size();
if(n<=0)
return;
int m=board[0].size();
if(n<=0||m<=0)
return;
for(int i=0;i<n;i++)
{
if(board[i][0]=='O')//第一列
dfs(board,i,0,n,m);
if(board[i][m-1]=='O')//最後一列
dfs(board,i,m-1,n,m);
}
for(int j=0;j<m;++j)
{
if(board[0][j]=='O')
dfs(board,0,j,n,m);
if(board[n-1][j]=='O')
dfs(board,n-1,j,n,m);
}
for(int i=0;i<n;++i)
{
for(int j=0;j<m;++j)
{
if(board[i][j]=='O')
board[i][j]='X';
}
}
for(int i=0;i<n;++i)
{
for(int j=0;j<m;++j)
{
if(board[i][j]=='A')
board[i][j]='O';
}
}
}
};
Leetcode200.島嶼數量
其實就是連通區域的個數。
給定一個由 '1'(陸地)和 '0'(水)組成的的二維網格,計算島嶼的數量。一個島被水包圍,並且它是通過水平方向或垂直方向上相鄰的陸地連接而成的。你可以假設網格的四個邊均被水包圍。
示例 1:
輸入:
11110
11010
11000
00000輸出: 1
示例 2:輸入:
11000
11000
00100
00011輸出: 3
class Solution {
public:
void dfs(vector<vector<char>>& grid,vector<vector<int>>&vis,int x,int y,int n,int m)
{
if(x<0||x>=n||y<0||y>=m||grid[x][y]=='0')
return;
if(grid[x][y]=='1'&&vis[x][y]==0)
{
vis[x][y]=1;
dfs(grid,vis,x-1,y,n,m);
dfs(grid,vis,x+1,y,n,m);
dfs(grid,vis,x,y-1,n,m);
dfs(grid,vis,x,y+1,n,m);
}
}
int numIslands(vector<vector<char>>& grid) {
//有點就連通的也就是幾個連通圖 上下左右連着都是1的有幾個模塊
if(grid.size()<=0)//空的
return 0;
int n=grid.size();
int m=grid[0].size();
vector<vector<int>>vis(n,vector<int>(m,0));
int cnt=0;
for(int i=0;i<n;++i)
{
for(int j=0;j<m;++j)
{
if(grid[i][j]=='1'&&vis[i][j]==0)
{
dfs(grid,vis,i,j,n,m);
++cnt;
}
}
}
return cnt;
}
};
Leetcode695.島嶼的最大面積
給定一個包含了一些 0 和 1 的非空二維數組 grid 。
一個 島嶼 是由一些相鄰的 1 (代表土地) 構成的組合,這裏的「相鄰」要求兩個 1 必須在水平或者豎直方向上相鄰。你可以假設 grid 的四個邊緣都被 0(代表水)包圍着。
找到給定的二維數組中最大的島嶼面積。(如果沒有島嶼,則返回面積爲 0 。)
示例 1:
[[0,0,1,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,1,1,0,1,0,0,0,0,0,0,0,0],
[0,1,0,0,1,1,0,0,1,0,1,0,0],
[0,1,0,0,1,1,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0]]
對於上面這個給定矩陣應返回 6。注意答案不應該是 11 ,因爲島嶼只能包含水平或垂直的四個方向的 1 。示例 2:
[[0,0,0,0,0,0,0,0]]
對於上面這個給定的矩陣, 返回 0。
注意: 給定的矩陣grid 的長度和寬度都不超過 50。
class Solution {
public:
void dfs(vector<vector<int>>&grid,vector<vector<int>>&vis,int x,int y,int n,int m,int &cnt)
{
if(x<0||x>=n||y<0||y>=m||grid[x][y]==0)
return;
if(grid[x][y]==1&&vis[x][y]==0)
{
vis[x][y]=1;
++cnt;
dfs(grid,vis,x-1,y,n,m,cnt);
dfs(grid,vis,x+1,y,n,m,cnt);
dfs(grid,vis,x,y-1,n,m,cnt);
dfs(grid,vis,x,y+1,n,m,cnt);
}
}
int maxAreaOfIsland(vector<vector<int>>& grid) {
int n=grid.size();
if(n<=0)
return 0;
int m=grid[0].size();
vector<vector<int>>vis(n,vector<int>(m,0));
int res=0;
int cnt=0;
for(int i=0;i<n;++i)
{
for(int j=0;j<m;++j)
{
if(grid[i][j]==1&&vis[i][j]==0)
{
cnt=0;
dfs(grid,vis,i,j,n,m,cnt);
if(cnt>res)
res=cnt;
}
}
}
return res;
}
};