インタビューでよくある質問: LeetCode 島の質問 DFS 島番号、境界線、最大面積

DFS(深さ優先検索)について

DFS は通常、ツリーやグラフなどの構造を検索することはわかっていますが、そのようなグリッド状の場所を検索するにはどのように使用すればよいでしょうか?

次のグリッド:
ここに画像の説明を挿入

グリッド問題は、m×n個の小正方形からなる格子であり、各小正方形は上下左右の4つの正方形に隣接していると考えられ、このような格子上で何らかの探索を行う必要がある。

DFSの構造

グリッドの問題は、バイナリ ツリーの構造よりも少し複雑です。グリッド上に DFS を記述するには、まずバイナリ ツリーの DFS についてよく理解しておく必要があります。バイナリ ツリーの DFS には、フロント、ミドル、
およびバイナリ ツリーのバック オーダー トラバース。

バイナリ ツリー DFS の基本構造:

void DFS(TreeNode root) {
    
    
    //判断终止条件
    if (root == null) {
    
    
        return;
    }
    // 访问两个相邻结点:左子结点、右子结点
    DFS(root->left);
    DFS(root->right);
}

バイナリ ツリーの DFS には 2 つの主要な点があることを理解するのは難しくありません。

  • 終了条件判定
  • 隣接するノードを訪問する

グリッド構造も同様で、グリッドを中心として上下左右に移動する: グリッドの
ここに画像の説明を挿入
終了条件

  • グリッドの境界を越えて
  • このグリッドはすでに訪問されています(グリッドが訪問されているかどうかを判断しない場合、無限ループの危険があります)

グリッド DFS の基本構造:

void dfs(vector<vector<int> grid, int i, int j) {
    
    
    // 终止条件判断
    // 如果坐标超出了网格范围,直接返回
    if (终止条件)) {
    
    
        return;
    }
    // 如果这个格子不是岛屿,直接返回
    if (grid[i][j] != 1) {
    
    
        return;
    }
    grid[i][j] = 2; // 将格子标记为「已遍历过」
    // 访问上、下、左、右四个相邻结点
    dfs(grid, i - 1, j);
    dfs(grid, i + 1, j);
    dfs(grid, i, j - 1);
    dfs(grid, i, j + 1);
}

島の数

「1」(陸地) と「0」(水域) で構成される 2D グリッドがある場合、グリッド内の島の数を数えてください。
島は常に水に囲まれており、各島は水平または垂直に隣接する土地を接続することによってのみ形成されます。
また、メッシュの四方すべてが水で囲まれていると考えることができます。

出典: LeetCode (LeetCode)島の数
ここに画像の説明を挿入
これは非常に典型的なグリッド問題であり、実際に解決するのは非常に簡単です。

アイデア: グリッド配列を順番に走査します。グリッド配列が '1' の場合は、DFS 再帰に入り、再帰で隣接するグリッドを走査し、グリッドの番号を '2' に変更します。再帰は終了し、走査を続けます。グリッド配列。
DFS に渡される関数パラメータのグリッド配列は次のとおりである必要があります。引用、グリッドによって計算されたアイランドを正確にマークできるようにすることで、グリッド配列のトラバースが同じアイランドに遭遇することを防ぎ、継続的な判断を行うことができます。

参照コード:

class Solution {
    
    
public:
    void DFS(vector<vector<char>>& grid,int i,int j)
    {
    
    
    	//终止条件判断
        if(i < 0 || i >= grid.size() ||
           j < 0 || j >= grid[0].size() || grid[i][j] != '1'){
    
    
            return;
        }
        grid[i][j]='2';//已遍历标记
        DFS(grid,i+1,j);
        DFS(grid,i-1,j);
        DFS(grid,i,j+1);
        DFS(grid,i,j-1);
    }
    int numIslands(vector<vector<char>>& grid) {
    
    
        int sum=0;
        for(int i=0;i<grid.size();i++)
        {
    
    
            for(int j=0;j<grid[0].size();j++)
            {
    
    
                if(grid[i][j]=='1')//只有'1'才进入 '0' 与 '2' 都不进入
                {
    
    
                    sum++;
                    DFS(grid,i,j);
                }
            }
        }
        return sum;
    }
};

島の外周

行 x 列の 2 次元グリッド マップ グリッドを指定すると、grid[i][j] = 1 は土地を意味し、grid[i][j] = 0 は水を意味します。
グリッド内のセルは水平方向と垂直方向に接続されています (斜めには接続されていません)。グリッド全体は完全に水に囲まれていますが、島は 1 つだけあります (つまり、陸地を表す 1 つ以上の接続されたグリッドで構成される島)。
島には「湖」はありません(「湖」とは島内の水域を指し、島の周囲の水域とはつながっていません)。格子は一辺の長さが 1 の正方形です。グリッドは長方形で、幅と高さが 100 を超えてはなりません。この島の周囲を計算してください。

出典: LeetCode による島の周囲

ここに画像の説明を挿入
この質問は、主に境界の判断に関する上記のトラバースのアイデアに似ています。

周長判定案1:
ここに画像の説明を挿入
周長判定案2:
ここに画像の説明を挿入
参考コード:

class Solution {
    
    
public:
    int DFS(vector<vector<int>>& grid,int i,int j)
    {
    
    
    	//边界+1
        if(i<0 || i>=grid.size() || j<0 || j>=grid[0].size())
        {
    
    
            return 1;
        }
        //'0'海洋+1
        if(grid[i][j]==0)
        {
    
    
            return 1;
        }
        //已遍历过的陆地+0
        if(grid[i][j]!=1)
        {
    
    
            return 0;
        }
        grid[i][j]=2;
        return DFS(grid,i-1,j)+
        DFS(grid,i+1,j)+
        DFS(grid,i,j-1)+
        DFS(grid,i,j+1);
    }
    int islandPerimeter(vector<vector<int>>& grid) {
    
    
        for(int i=0;i<grid.size();i++)
        {
    
    
            for(int j=0;j<grid[0].size();j++)
            {
    
    
                if(grid[i][j]==1)
                {
    
    
                    return DFS(grid,i,j);
                }
            }
        }
        return 0;
    }
};

島の最大の面積

サイズ mxn のバイナリ行列グリッドが与えられます。
島とは、いくつかの隣接する 1 (陸地を表す) の組み合わせです。ここでの「隣接」とは、2 つの 1 が水平方向または垂直方向の 4 方向に隣接している必要があります。グリッドの 4 つの端すべてがゼロ (水を表す) で囲まれていると仮定できます。
島の面積は、島内の値が 1 であるセルの数です。
グリッド内の最大の島の面積を計算して返します。島がない場合、返される面積は0です。
出典:LeetCode(リートコード)島の最大面積

ここに画像の説明を挿入
ここに画像の説明を挿入
この質問も素朴な疑問ですが、この種のグリッド DFS 問題は、DFS の構造を明確にしてひょうたん通りに書けば、実はそれほど難しくありません。

アイデア: 順次走査し、最大領域を反復する
参考コード:

class Solution {
    
    
public:
    int DFS(vector<vector<int>>& grid,int i,int j)
    {
    
    
        if(i<0 || i>=grid.size() || j<0 || j>=grid[0].size() || grid[i][j]!=1)
        {
    
    
            return 0;
        }
        grid[i][j]=2;
        return 1+DFS(grid,i+1,j)+
                DFS(grid,i-1,j)+
                DFS(grid,i,j+1)+
                DFS(grid,i,j-1);
    }
    int maxAreaOfIsland(vector<vector<int>>& grid) {
    
    
        int max=0;
        for(int i=0;i<grid.size();i++)
        {
    
    
            for(int j=0;j<grid[0].size();j++)
            {
    
    
                if(grid[i][j]==1)
                {
    
    
                    int sum=DFS(grid,i,j);
                    if(sum>max)
                    {
    
    
                        max=sum;
                    }
                }
            }
        }
        return max;
    }
};

おすすめ

転載: blog.csdn.net/DEXTERFUTIAN/article/details/129880606