[C++][leetcode]dfs+搜索問題

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;


    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章