グラフ理論アルゴリズム(6):LeetCodeグラフ理論アルゴリズム演習(785.二者間グラフの判断、695。島の最大面積、フラッドフィルアルゴリズム、ユニオン検索)

この章の内容は、JavaのGithubコードウェアハウスに実装されています:https ://github.com/ZhekaiLi/Code/tree/main/Graph/src

記事の写真を表示するには、科学的なインターネットアクセスが必要になる場合があります。githubを使用して画像を管理しているため、ロードできない状況が発生した場合は、壁を裏返してください

[参照]imoocMr. Bobo:楽しいアルゴリズムシリーズ-インタビューとプロモーションのためのグラフ理論の要点(Java版)

[以前のブログへのリンク]
グラフ理論アルゴリズム(1、2):グラフの分類、グラフの基本概念(無向グラフと有向グラフ、重み付けされていないグラフ、非循環グラフ、完全なグラフ、二者間グラフ、単純なグラフ、接続されたグラフコンポーネント、スパングラフ、サブグラフ、親グラフのツリー)
グラフ理論アルゴリズム(3):グラフの基本表現(隣接行列、隣接リスト、隣接行列と隣接リストの比較)
グラフ理論アルゴリズム(4):グラフの最初の深さトラバーサルDFS
グラフ理論アルゴリズム(5):グラフ幅ファーストトラバーサルBFS
グラフ理論アルゴリズム(6):LeetCodeグラフ理論アルゴリズム演習(785.二者間グラフの判断、695。島の最大面積、フラッドフィルアルゴリズム、ユニオンチェック)

6LeetCodeグラフ理論アルゴリズムの演習

785.2部グラフの判断

セクション4.4を参照できます

javaの実装:LeetCode785_me.java(作成者はBFSを使用)

695.島の最大面積

この問題の核心はグラフモデリングです。これは、タイトルで指定された2次元配列からポイントとエッジの情報を抽出することです。私たちの目標は、次のマトリックスを配置することです

[[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]]

に変換

// AdjList[i] 储存结点i的邻接点
AdjList = [[1, 4, 8], [2, 7, 9], ...]

ただし、従来の隣接リストのノードは整数で表されますが、ステムマトリックスでは、ノードは2次元の位置パラメータで表されます。主な手順は次のとおりです。
(1)ノード情報を2次元からにマッピングします。一次元



(2)ノードに隣接するポイントがあるかどうかを判断します



(3)無向グラフの連結成分を解くための以前に書かれたアルゴリズムに従って、コードの本体を完成させます

セクション4.1を参照できます

Java実装v1:LeetCode695_me.java(LeetCodeは、私がユーザーの5.3%を打ち負かしたことを示しています...、なんてくだらないことです。比較的複雑なデータ構造が使用されている可能性がありますが、ロジックに関しては、個人的にはかなり問題ないと感じています)
Java実装v2:LeetCode695.java(より良いコード例)
最初に2D行列を変換してグラフ情報をHashSet入力し、次にdfsを使用します。コアコード:

private int[][] dirs = {
    
    {
    
    -1, 0}, {
    
    0, 1}, {
    
    1, 0}, {
    
    0, -1}}; // 四连通

private HashSet<Integer>[] constructGraph(){
    
    
    HashSet<Integer>[] g = new HashSet[R * C];
    for (int i = 0; i < g.length; i++)
        g[i] = new HashSet<>();

    for (int v = 0; v < g.length; v++) {
    
    
        int x = v / C, y = v % C; // 将一维信息转化为二维坐标
        if (grid[x][y] == 1) {
    
    
            for (int d = 0; d < 4; d++) {
    
    
                int nextx = x + dirs[d][0], nexty = y + dirs[d][1];
                if (inArea(nextx, nexty) && grid[nextx][nexty] == 1){
    
    
                    int next = nextx * C + nexty;
                    g[v].add(next);
                }}}}
    return g;
}

private int dfs(int v){
    
    
    visited[v] = true;
    int res = 1;
    for(int w: G[v]){
    
    
        if(!visited[w])
            res += dfs(w);
    }
    return res;
}

Java実装v3:LeetCode695_plus.java
入力された2次元行列を直接使用してグラフ情報を保存し、dfsを変換して2次元入力に適したものにします。コアコード:

private int dfs(int x, int y){
    
    
    visited[x][y] = true;
    int res = 1;
    for(int d = 0; d < 4; d++){
    
    
        int nextx = x + dirs[d][0], nexty = y + dirs[d][1];
        if(inArea(nextx, nexty) && !visited[nextx][nexty] && grid[nextx][nexty] == 1)
            res += dfs(nextx, nexty);
    }
    return res;
}

6.1フラッドフィルアルゴリズム

前のセクションの最後のコード(Java実装v3)は、フラッドフィルアルゴリズムとも呼ばれます。これは、エッジに基づく元の伝播方法が座標系で4方向に伝播するように変更されていることを除いて、基本的にdfsと同じです。 。。例は次のとおりです。



塗りつぶしの適用

psの魔法の杖とマインスイーパゲーム



LeetCodeの関連質問

200.島の
数1020.飛び地の数
130.周辺地域
733.画像レンダリング(塗りつぶし)
1034。境界線の色付け
529.マインスイーパゲーム
827.最大の人工島[ハード]

6.2接続とユニオン

class UF{
    
    
    private int[] parent;

    public UF(int n){
    
    
        parent = new int[n];
        for(int i = 0 ; i < n ; i ++)
            parent[i] = i;
    }

    public int find(int p){
    
    
        if( p != parent[p] )
            parent[p] = find( parent[p] );
        return parent[p];
    }

    public boolean isConnected(int p , int q){
    
    
        return find(p) == find(q);
    }

    public void unionElements(int p, int q){
    
    
        int pRoot = find(p);
        int qRoot = find(q);
        if( pRoot == qRoot )
            return;
        parent[pRoot] = qRoot;
    }
}

以下に、図とコードの組み合わせでユニオンクエリセットの作成と実行プロセスを示します。

UF uf = new UF(6);


uf.unionElements(2, 1);
uf.unionElements(3, 1);
uf.unionElements(5, 4);
uf.unionElements(6, 4);


uf.unionElements(4, 1);


find(int p)この関数は、ノードpのルートノードを返すだけでなく、実行するたびにノードpの親ノードをそのルートノードに直接変更できることに注意してください。このような機能の実装により、接続の長いリストを回避できます

さらに、任意の要素のコレクション内の要素の数を見つけることをサポートするようにUFクラスます

class UF{
    
    
    private int[] parent;
    private int[] sz; // 1. 我们需要一个 sz 数组,存储以第 i 个元素为根节点的集合的元素个数。

    public UF(int n){
    
    
        parent = new int[n];
        sz = new int[n];
        for(int i = 0 ; i < n ; i ++){
    
    
            parent[i] = i;
            sz[i] = 1; // 2. 初始化,每个 sz[i] = 1
        }
    }

    public int find(int p){
    
     // 没有变化... }
    public boolean isConnected(int p , int q){
    
     // 没有变化 }

    public void unionElements(int p, int q){
    
    
        int pRoot = find(p);
        int qRoot = find(q);
        if( pRoot == qRoot )
            return;
        parent[pRoot] = qRoot;
        // 3. 维护 sz:把 qRoot 的集合元素数量加上 pRoot 的集合元素数量
        sz[qRoot] += sz[pRoot];
    }

    // 4. 最后,设计一个接口让用户可以查询到任意一个元素 p 所在的集合的元素个数 
    public int size(int p){
    
    
        return sz[find(p)]; // 使用 p 所在的集合的根节点查找相应的元素个数
    }
}

フラッドフィル+ユニオンを使用したLeetCodeの演習

695.島の最大面積

おすすめ

転載: blog.csdn.net/weixin_43728138/article/details/118993955