【算法面试通关40讲】53 - 面试题:岛屿的个数&朋友圈(上)54 - 面试题:岛屿的个数&朋友圈(下)

Leetcode-200. 岛屿数量

给定一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

示例 1:

输入:
11110
11010
11000
00000

输出: 1

示例 2:

输入:
11000
11000
00100
00011

输出: 3

解法:1. 染色(flood fill)a. 遍历所有的节点,如果节点为1,count++,然后将这个节点和附近的所有1节点全部变为0,使用dfs或者bfs 2. 并查集,a. 初始化,针对所有的1节点,将root指向自己,b. 遍历所有的节点,相邻的1节点合并,0不做处理,c. 遍历查询有多少不同的parent,时间复杂度O(MN)

  • Java
    dfs
class Solution {
    public int numIslands(char[][] grid) {
        int count = 0;
        for (int i=0;i<grid.length;i++) {
            for (int j=0;j<grid[0].length;j++) {
                if (grid[i][j]=='1') {
                    this.dfs(grid, i, j);
                    count += 1;
                }
            }
        }
        return count;
    }
    public void dfs(char[][] grid, int i, int j) {
        if (i<0 || i>= grid.length || j<0 || j>= grid[0].length || grid[i][j]!='1') return ;
        grid[i][j] = 0;
        this.dfs(grid, i+1, j);
        this.dfs(grid, i, j+1);
        this.dfs(grid, i-1, j);
        this.dfs(grid, i, j-1);
        return ;
    }
}
  • Java
    bfs
class Solution {
    int[] dx = {0,0,-1,1};
    int[] dy = {-1,1,0,0};
    public int numIslands(char[][] grid) {
        int count=0;
        for(int i=0;i<grid.length;i++)
            for(int j=0;j<grid[0].length;j++){
                if(grid[i][j]=='1'){
                    bfsFill(grid,i,j);
                    count++;
                }
            }
        return count;
    }
    private void bfsFill(char[][] grid,int x, int y){
        grid[x][y]='0';
        int n = grid.length;
        int m = grid[0].length;
        Queue<Integer> queue = new LinkedList<Integer>();  
        int code = x*m+y;  
        queue.offer(code);  
        while(!queue.isEmpty())  
        {  
            code = queue.poll();  
            int i = code/m;  
            int j = code%m; 
            for (int k=0;k<4;k++) {
                if (this.isValid(grid, i+dx[k], j+dy[k])) {
                    queue.offer((i+dx[k])*m+(j+dy[k]));
                    grid[i+dx[k]][j+dy[k]] = '0';
                }
            }
        } 
    }
    public boolean isValid(char[][] grid,int i,int j) {
        return (i>=0 && i<grid.length && j>=0 && j<grid[0].length && grid[i][j]=='1');
    }
}

并查集

class Solution {
  class UnionFind {
    int count; // # of connected components
    int[] parent;
    int[] rank;

    public UnionFind(char[][] grid) { // for problem 200
      count = 0;
      int m = grid.length;
      int n = grid[0].length;
      parent = new int[m * n];
      rank = new int[m * n];
      for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
          if (grid[i][j] == '1') {
            parent[i * n + j] = i * n + j;
            ++count;
          }
          rank[i * n + j] = 0;
        }
      }
    }

    public int find(int i) { // path compression
      if (parent[i] != i) parent[i] = find(parent[i]);
      return parent[i];
    }

    public void union(int x, int y) { // union with rank
      int rootx = find(x);
      int rooty = find(y);
      if (rootx != rooty) {
        if (rank[rootx] > rank[rooty]) {
          parent[rooty] = rootx;
        } else if (rank[rootx] < rank[rooty]) {
          parent[rootx] = rooty;
        } else {
          parent[rooty] = rootx; rank[rootx] += 1;
        }
        --count;
      }
    }

    public int getCount() {
      return count;
    }
  }

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

    int nr = grid.length;
    int nc = grid[0].length;
    int num_islands = 0;
    UnionFind uf = new UnionFind(grid);
    for (int r = 0; r < nr; ++r) {
      for (int c = 0; c < nc; ++c) {
        if (grid[r][c] == '1') {
          grid[r][c] = '0';
          if (r - 1 >= 0 && grid[r-1][c] == '1') {
            uf.union(r * nc + c, (r-1) * nc + c);
          }
          if (r + 1 < nr && grid[r+1][c] == '1') {
            uf.union(r * nc + c, (r+1) * nc + c);
          }
          if (c - 1 >= 0 && grid[r][c-1] == '1') {
            uf.union(r * nc + c, r * nc + c - 1);
          }
          if (c + 1 < nc && grid[r][c+1] == '1') {
            uf.union(r * nc + c, r * nc + c + 1);
          }
        }
      }
    }

    return uf.getCount();
  }
}

  • Python
    dfs
class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        self.grid = grid
        count = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if (grid[i][j]=='1'):
                    self.dfs(i, j)
                    count += 1
        return count
    def dfs(self, i, j):
        if i<0 or i>=len(self.grid) or j<0 or j>=len(self.grid[0]) or self.grid[i][j]!='1' : return 
        self.grid[i][j] = 0
        self.dfs(i-1, j)
        self.dfs(i+1, j)
        self.dfs(i, j-1)
        self.dfs(i, j+1)
  • Python
    bfs
class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        self.dx = [0,0,-1,1]
        self.dy = [-1,1,0,0]
        if not grid: return 0
        self.grid = grid 
        count = 0
        for i in range(len(self.grid)):
            for j in range(len(self.grid[0])):
                if (grid[i][j]=='1'):
                    self.bfs(i, j)
                    count += 1
        return count
    def bfs(self, i, j):
        self.queue = [(i,j)]
        while self.queue:
            i, j = self.queue.pop(0)
            for k in range(4):
                if self.isValid(i+self.dx[k], j+self.dy[k]):
                    self.queue.append((i+self.dx[k], j+self.dy[k]))
                    self.grid[i+self.dx[k]][j+self.dy[k]] = '0'
            
    def isValid(self, i, j):
        return 0<=i<len(self.grid) and 0<=j<len(self.grid[0]) and self.grid[i][j]=='1'

并查集

class UnionFind(object):
    def __init__(self, grid):
        m, n = len(grid), len(grid[0])
        self.count = 0
        self.parent = [-1] * (m*n)
        self.rank = [0] * (m*n)
        for i in range(m):
            for j in range(n):
                if grid[i][j] == '1':
                    self.parent[i*n+j] = i*n+j
                    self.count += 1
    def find(self, i):
        if self.parent[i]!= i:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]
    def union(self, x, y):
        rootx = self.find(x)
        rooty = self.find(y)
        if rootx!=rooty:
            if self.rank[rootx]>self.rank[rooty]:
                self.parent[rooty] = rootx
            elif self.rank[rooty]>self.rank[rootx]:
                self.parent[rootx] = rooty
            else:
                self.parent[rooty] = rootx
                self.rank[rootx] += 1
            self.count -= 1
class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        if not grid : return 0
        uf = UnionFind(grid)
        directions = [(0, 1), (0, -1), (-1, 0), (1, 0)]
        m, n = len(grid), len(grid[0])
        for i in range(m):
            for j in range(n):
                if grid[i][j]=='0':continue
                for d in directions:
                    x, y = i+d[0], j+d[1]
                    if 0<=x<m and 0<=y<n and grid[x][y]=='1':
                        uf.union(i*n+j, x*n+y)
        return uf.count

Leetcode-547. 朋友圈

班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。

给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。

示例 1:

输入: 
[[1,1,0],
 [1,1,0],
 [0,0,1]]
输出: 2 
说明:已知学生0和学生1互为朋友,他们在一个朋友圈。
第2个学生自己在一个朋友圈。所以返回2。

示例 2:

输入: 
[[1,1,0],
 [1,1,1],
 [0,1,1]]
输出: 1
说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。

注意:

  1. N 在[1,200]的范围内。
  2. 对于所有学生,有M[i][i] = 1。
  3. 如果有M[i][j] = 1,则有M[j][i] = 1。

解法:1. dfs,遍历层,如果层被访问过,则count+1,visited[i] = 1。时间复杂度O(N^2),空间复杂度O(N)

  • Java
    dfs
class Solution {
    public int findCircleNum(int[][] M) {
        int count = 0;
        int[] visited = new int[M.length];
        for (int i=0;i<M.length;i++) {
            if (visited[i]==0) {
                this.dfs(M, visited, i);
                count++;
            }
        }
        return count;
    }
    public void dfs(int[][] M, int[] visited, int i) {
        for (int j=0;j<M[0].length;j++) {
            if (M[i][j]==1 && visited[j]==0) {
                visited[j] = 1;
                this.dfs(M, visited, j);
            }
        }
    }
}

-bfs

public class Solution {
    public int findCircleNum(int[][] M) {
        int[] visited = new int[M.length];
        int count = 0;
        Queue < Integer > queue = new LinkedList < > ();
        for (int i = 0; i < M.length; i++) {
            if (visited[i] == 0) {
                queue.add(i);
                while (!queue.isEmpty()) {
                    int s = queue.remove();
                    visited[s] = 1;
                    for (int j = 0; j < M.length; j++) {
                        if (M[s][j] == 1 && visited[j] == 0)
                            queue.add(j);
                    }
                }
                count++;
            }
        }
        return count;
    }
}

  • 并查集(慢,不推荐)
public class Solution {
    int find(int parent[], int i) {
        if (parent[i] == -1)
            return i;
        return find(parent, parent[i]);
    }

    void union(int parent[], int x, int y) {
        int xset = find(parent, x);
        int yset = find(parent, y);
        if (xset != yset)
            parent[xset] = yset;
    }
    public int findCircleNum(int[][] M) {
        int[] parent = new int[M.length];
        Arrays.fill(parent, -1);
        for (int i = 0; i < M.length; i++) {
            for (int j = 0; j < M.length; j++) {
                if (M[i][j] == 1 && i != j) {
                    union(parent, i, j);
                }
            }
        }
        int count = 0;
        for (int i = 0; i < parent.length; i++) {
            if (parent[i] == -1)
                count++;
        }
        return count;
    }
}

作者:LeetCode
链接:https://leetcode-cn.com/problems/friend-circles/solution/peng-you-quan-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • Python
    dfs
class Solution:
    def findCircleNum(self, M: List[List[int]]) -> int:
        self.visited = [0] * len(M)
        count = 0
        for i in range(len(M)):
            if self.visited[i]==0:
                self.dfs(M, i)
                count += 1
        return count
    
    def dfs(self, M, i):
        for j in range(len(M)):
            if M[i][j]==1 and self.visited[j]==0:
                self.visited[j] = 1
                self.dfs(M, j)
  • bfs
class Solution:
    def findCircleNum(self, M: List[List[int]]) -> int:
        if not M:return 0
        count = 0
        visited = [0]*len(M)
        queue = []
        for i in range(len(M)):
            if visited[i]==0:
                queue.append(i)
                while queue:
                    level = queue.pop(0)
                    visited[level] = 1
                    for j in range(len(M)):
                        if M[level][j]==1 and visited[j]==0:
                            queue.append(j)
                count += 1
        return count
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值