Leetcode每日一題-200. 島嶼數(shù)量

給你一個(gè)由 '1'(陸地)和 '0'(水)組成的的二維網(wǎng)格,請你計(jì)算網(wǎng)格中島嶼的數(shù)量。

島嶼總是被水包圍,并且每座島嶼只能由水平方向和/或豎直方向上相鄰的陸地連接形成。

此外,你可以假設(shè)該網(wǎng)格的四條邊均被水包圍。

示例 1:

輸入:
11110
11010
11000
00000
輸出: 1

示例 2:

輸入:
11000
11000
00100
00011
輸出: 3
解釋: 每座島嶼只能由水平和/或豎直方向上相鄰的陸地連接而成。

解題思路

島嶼問題是網(wǎng)格類型的典型案例,主要考察DFS(深度優(yōu)先搜索)和BFS(廣度優(yōu)先搜索)以及Union find(并查集)。

DFS寫法(使用迭代和遞歸):遍歷整個(gè)網(wǎng)格,如果一個(gè)位置是'1',則以該店進(jìn)行深度搜索查詢,計(jì)數(shù)的同時(shí)把位置'1'置為'0'(同時(shí)需要注意邊界問題,防止出界)。

class Solution {
    //dfs
    private int rows;
    private int cols;
    private int count = 0;
    public int numIslands(char[][] grid) {
        
        if(grid == null || grid.length == 0) return 0;

        rows = grid.length;
        cols = grid[0].length;
        for(int i = 0 ; i < rows ; i++)
        {
            for(int j = 0 ; j < cols ; j++)
            {
                if(grid[i][j] == '0') continue;

                count++;
                dfs(grid,i,j);
            }
        }

        return count;
    }

    //每一個(gè)臨界的'1'都要被重置為'0',直到遍歷完為止
    private void dfs(char[][] grid, int i, int j)
    {
        if(i < 0 || j < 0 || i >= rows || j >= cols) return;

        if(grid[i][j] == '1') 
        {
            grid[i][j] = '0';
            dfs(grid,i-1,j);
            dfs(grid,i+1,j);
            dfs(grid,i,j-1);
            dfs(grid,i,j+1);
        }
    }
}

運(yùn)算結(jié)果:執(zhí)行用時(shí):2ms,內(nèi)存消耗:42MB

BFS寫法(使用隊(duì)列):掃描整個(gè)網(wǎng)格,如果位置是'1',則加入隊(duì)列,并以該位置開始進(jìn)行廣度搜索,在廣度搜索中每一個(gè)'1'都會(huì)被重置為'0',知道隊(duì)列為空,搜索結(jié)束。

class Solution {
    public int numIslands(char[][] grid) {
        if(grid == null || grid.length == 0) return 0;

        int rows = grid.length;
        int cols = grid[0].length;
        int count = 0;

        for(int i=0;i<rows;i++)
        {
            for(int j=0;j<cols;j++)
            {
                if(grid[i][j] == '1')
                {
                    grid[i][j] = '0';
                    count++;
                    Queue<Integer> queue = new LinkedList<Integer>();
                    queue.offer(i*cols+j);
                    //廣度優(yōu)先搜索
                    while(!queue.isEmpty())
                    {
                        int index = queue.poll();
                        int x = index/cols;
                        int y = index%cols;

                        if(x-1>=0 &&grid[x-1][y] == '1') 
                        {
                            grid[x-1][y] = '0';
                            queue.offer((x-1)*cols+y);
                        }
                        if(x+1<rows &&grid[x+1][y] == '1')
                        {
                            grid[x+1][y] = '0';
                            queue.offer((x+1)*cols+y);
                        }
                        if(y-1>=0 &&grid[x][y-1] == '1')
                        {
                            grid[x][y-1] = '0';
                            queue.offer(x*cols+(y-1));
                        }
                        if(y+1<cols &&grid[x][y+1] == '1')
                        {
                            grid[x][y+1] = '0';
                            queue.offer(x*cols+(y+1));
                        }
                    }
                }

            }
        }
        return count;
    }
}

運(yùn)算結(jié)果:執(zhí)行用時(shí):6ms,內(nèi)存消耗:42.4MB

union find(并查集):并查集這種數(shù)據(jù)結(jié)構(gòu)主要用于數(shù)據(jù)的分類和判斷兩個(gè)元素是否屬于同一類別,可以借助該思想對題目中的滿足條件的島嶼進(jìn)行合并。

class Solution {
    
    //union find
    public int numIslands(char[][] grid) {
    
        if(grid == null || grid.length == 0) return 0;
        
        int row = grid.length;
        int col = grid[0].length;
        
        UnionFind uf = new UnionFind(grid);
        
        for(int i=0;i<row;i++)
        {
            for(int j=0;j<col;j++)
            {
                if(grid[i][j] == '1')
                {
                    grid[i][j] = '0';
                    
                    if(i-1 >= 0 && grid[i-1][j] == '1')
                    {
                        uf.union(i*col+j,(i-1)*col+j);
                    }
                    if(i+1 < row && grid[i+1][j] == '1')
                    {
                        uf.union(i*col+j,(i+1)*col+j);
                    }
                    if(j-1 >= 0 && grid[i][j-1] == '1')
                    {
                        uf.union(i*col+j,i*col+j-1);
                    }
                    if(j+1 < col && grid[i][j+1] == '1')
                    {
                        uf.union(i*col+j,i*col+j+1);
                    }
                }
            }
        }
        
        return uf.getCount();
    }
    
    class UnionFind
    {
        private int[] parent;
        private int[] rank;
        private int count = 0;
        
        public UnionFind(char[][] grid)
        {

            int row = grid.length;
            int col = grid[0].length;
            
            parent = new int[row*col];
            rank = new int[row*col];
            
            for(int i=0;i<row;i++)
            {
                for(int j=0;j<col;j++)
                {
                    if(grid[i][j] == '1')
                    {
                        count++;
                        parent[i*col+j] = i*col+j;  //每個(gè)島嶼‘1’都是一個(gè)集合,剩下的就是集合的合并
                    }
                    
                    rank[i*col+j] = 0;
                }
            }
        }
        
        //遞歸找到root,方便后面union方法中x和root直接建立聯(lián)系,壓縮路徑
        public int find(int x)
        {
            if(x != parent[x]) parent[x] = find(parent[x]);
            return parent[x];
        }
        
        public void union(int x,int y)
        {
            int rootX = find(x);
            int rootY = find(y);
            
            if(rootX != rootY)
            {
                //層級小的歸并到層級大的集合上
                if(rank[rootX] < rank[rootY])
                {
                    parent[rootX] = rootY; 
                }else if(rank[rootX] > rank[rootY])
                {
                    parent[rootY] = rootX; 
                }else
                {
                    parent[rootY] = rootX; 
                    rank[rootX] += 1; 
                }
                
                //去除重復(fù)的關(guān)聯(lián)島嶼
                count--;
            }
        }
        
        public int getCount()
        {
            return count;
        }
        
        
    }
}

執(zhí)行結(jié)果:執(zhí)行用時(shí) : 6 ms 內(nèi)存消耗 :42 MB

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容