【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。

547. 省份数量

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。

省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。

给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。

返回矩阵中 省份 的数量。

 

示例 1:


输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出:2
示例 2:


输入:isConnected = [[1,0,0],[0,1,0],[0,0,1]]
输出:3
 

提示:

1 <= n <= 200
n == isConnected.length
n == isConnected[i].length
isConnected[i][j] 为 1 或 0
isConnected[i][i] == 1
isConnected[i][j] == isConnected[j][i]
通过次数165,040提交次数266,697

 

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/friend-circle
链接:https://leetcode-cn.com/problems/number-of-provinces
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

 

思路

并查集的裸题

  public static int findCircleNum2(int[][] isConnected) {
        int lens = isConnected.length;
        int[] parent = new int[lens];
        for (int i=0; i<lens; i++) {
            parent[i] = i;
        }
        for (int i=0; i<lens; i++) {
            for (int j=i+1; j<lens; j++) {
                if (isConnected[i][j] ==1) {
                    union(parent, i, j);
                }
            }
        }
        int circles = 0;
        for (int i=0; i<lens; i++) {
            if (parent[i] == i) {
                circles++;
            }
        }
        return circles;
    }

    private static void union(int[] parent, int index1, int index2) {
        parent[find(parent, index1)] = find(parent, index2);
    }

    private static int find(int[] parent, int index) {
        if (parent[index] != index) {
            parent[index] = find(parent, parent[index]);
        }
        return parent[index];
    }

 

解题思路二 深度搜索

    public static int findCircleNum(int[][] isConnected) {
        int lens = isConnected.length;
        boolean[] hasVisited=new boolean[lens];
        int nums = 0;

        for(int i=0; i<lens; i++) {
            if (hasVisited[i] == false) {
                hasVisited[i] =true;
                nums++;
                dfs(isConnected, i, hasVisited);
            }
        }
        return nums;
    }

    private static void dfs(int[][] isConnected, int index, boolean[] hasVisited) {
        for (int i=0; i<isConnected[0].length; i++) {
            if (isConnected[i][index] == 1 && hasVisited[i] == false) {
                hasVisited[i] = true;
                dfs(isConnected, i, hasVisited);
            }
        }
    }

 

 

200. 岛屿数量

 

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

 

示例 1:

输入:grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
输出:1
示例 2:

输入:grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出:3
 

提示:

m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j] 的值为 '0' 或 '1'

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-islands
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


方法一:深度优先搜索

class Solution {
    void dfs(char[][] grid, int r, int c) {
        int nr = grid.length;
        int nc = grid[0].length;

        if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') {
            return;
        }

        grid[r][c] = '0';
        dfs(grid, r - 1, c);
        dfs(grid, r + 1, c);
        dfs(grid, r, c - 1);
        dfs(grid, r, c + 1);
    }

    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;
        for (int r = 0; r < nr; ++r) {
            for (int c = 0; c < nc; ++c) {
                if (grid[r][c] == '1') {
                    ++num_islands;
                    dfs(grid, r, c);
                }
            }
        }

        return num_islands;
    }
}

 

 

方法二:广度优先搜索
class Solution {
    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;

        for (int r = 0; r < nr; ++r) {
            for (int c = 0; c < nc; ++c) {
                if (grid[r][c] == '1') {
                    ++num_islands;
                    grid[r][c] = '0';
                    Queue<Integer> neighbors = new LinkedList<>();
                    neighbors.add(r * nc + c);
                    while (!neighbors.isEmpty()) {
                        int id = neighbors.remove();
                        int row = id / nc;
                        int col = id % nc;
                        if (row - 1 >= 0 && grid[row-1][col] == '1') {
                            neighbors.add((row-1) * nc + col);
                            grid[row-1][col] = '0';
                        }
                        if (row + 1 < nr && grid[row+1][col] == '1') {
                            neighbors.add((row+1) * nc + col);
                            grid[row+1][col] = '0';
                        }
                        if (col - 1 >= 0 && grid[row][col-1] == '1') {
                            neighbors.add(row * nc + col-1);
                            grid[row][col-1] = '0';
                        }
                        if (col + 1 < nc && grid[row][col+1] == '1') {
                            neighbors.add(row * nc + col+1);
                            grid[row][col+1] = '0';
                        }
                    }
                }
            }
        }

        return num_islands;
    }
}
方法三:并查集

class Solution {
    class UnionFind {
        int count;
        int[] parent;
        int[] rank;

        public UnionFind(char[][] grid) {
            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) {
            if (parent[i] != i) parent[i] = find(parent[i]);
            return parent[i];
        }

        public void union(int x, int y) {
            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();
    }
}

 

 

1102. 得分最高的路径

 

给你一个 R 行 C 列的整数矩阵 A。矩阵上的路径从 [0,0] 开始,在 [R-1,C-1] 结束。

路径沿四个基本方向(上、下、左、右)展开,从一个已访问单元格移动到任一相邻的未访问单元格。

路径的得分是该路径上的 最小 值。例如,路径 8 → 4 → 5 → 9 的值为 4 。

找出所有路径中得分 最高 的那条路径,返回其 得分。

示例 1:

 
image.png

输入:[[5,4,5],[1,2,6],[7,4,6]]
输出:4
解释:
得分最高的路径用黄色突出显示。
示例 2:

 
image.png

输入:[[2,2,1,2,2,2],[1,2,2,2,1,2]]
输出:2
示例 3:

 
image.png

输入:[[3,4,6,3,4],[0,2,1,1,7],[8,8,3,2,7],[3,2,4,9,8],[4,1,2,0,0],[4,6,5,4,3]]
输出:3

思路:单纯用贪心取四个方向最大值,得不到正确结果。
dfs取所有的路径取min,超时。
本题应用dijstra算法。通过heap来存所有可达点的值,按该值排序。



作者:月下围城
链接:https://www.jianshu.com/p/01f2aa3fa945
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 
import java.util.LinkedList;
import java.util.List;

public class MaximumMinimumPath {
    static class Node{
        int row;
        int col;
        int val;

        public Node(int row, int col,  int val) {
            this.row = row;
            this.col = col;
            this.val = val;
        }
    }
    static class UnionFind {
        private int[] parent;
        private int count;
        public UnionFind(int count) {
            this.count = count;
            this.parent = new int[count];
            for(int i=0; i<count; ++i){
                parent[i] = i;
            }
        }
        private int find(int index) {
            assert (index>=0 && index <count);
            if (index != parent[index]) {
                return find(parent[index]);
            }
            return index;
        }
        public void union (int index1, int index2) {
            int index1Root = find(index1);
            int index2Root = find(index2);
            if (index1Root != index2Root) {
                parent[index1Root] = index2Root;
            }
        }

        public boolean isConnected(int index1, int index2) {
            return find(index1) == find(index2);
        }
    }


    public static int maximumMinimumPath(int[][] heights) {

        int row = heights.length;
        if (row == 0 ) {
            return 0;
        }
        int col = heights[0].length;
        if ( col == 0) {
            return 0;
        }
        int ans = Math.min(heights[0][0], heights[row-1][col-1]);

        List<Node> heap = new LinkedList<Node>();

        for(int i=0; i< row; ++i){
            for (int j= 0; j< col; ++j) {
                heap.add(new Node(i, j, heights[i][j]));
            }
        }
        heap.sort((node1, node2)->( node2.val - node1.val));
        UnionFind unionFind = new UnionFind(row * col);

        int[][] directs = new int[][] {{0, 1},{0, -1},{-1, 0},{1, 0}};
        int[][] tag = new int[row][col];
        int end = row * col -1;
        for (int i=0 ; i<heap.size(); ++i) {
            Node node = heap.get(i);
            ans = Math.min(ans, node.val);
            tag[node.row][node.col] = 1;
            int rootIndex = node.row * col + node.col;
            for (int[] dir: directs) {
                int tagRow = node.row + dir[0];
                int tagCol = node.col + dir[1];
                if (tagRow >= 0 && tagRow < row && tagCol >= 0 && tagCol < col && tag[tagRow][tagCol] == 1) {
                    int rootNindex = tagRow * col + tagCol;
                    unionFind.union(rootIndex, rootNindex);
                }
            }
            if (unionFind.isConnected(0, end)){
                break;
            }
        }
        return ans;
    }

    public static void main(String[] args) {
        int[][] heights = new int[][] {
                {5,4,5},
                {1,2,6},
                {7,4,6}};
        System.out.println(maximumMinimumPath(heights));
    }
}

 

 

leetcode 1135. 最低成本联通所有城市

想象一下你是个城市基建规划者,地图上有 N 座城市,它们按以 1 到 N 的次序编号。

给你一些可连接的选项 conections,其中每个选项 conections[i] = [city1, city2, cost] 表示将城市 city1 和城市 city2 连接所要的成本。(连接是双向的,也就是说城市 city1 和城市 city2 相连也同样意味着城市 city2 和城市 city1 相连)。

返回使得每对城市间都存在将它们连接在一起的连通路径(可能长度为 1 的)最小成本。该最小成本应该是所用全部连接代价的综合。如果根据已知条件无法完成该项任务,则请你返回 -1。

 

示例 1:

 

输入:N = 3, conections = [[1,2,5],[1,3,6],[2,3,1]]
输出:6
解释:
选出任意 2 条边都可以连接所有城市,我们从中选取成本最小的 2 条。
示例 2:

 

输入:N = 4, conections = [[1,2,3],[3,4,4]]
输出:-1
解释:
即使连通所有的边,也无法连接所有城市。

提示:

1 <= N <= 10000
1 <= conections.length <= 10000
1 <= conections[i][0], conections[i][1] <= N
0 <= conections[i][2] <= 10^5
conections[i][0] != conections[i][1]

https://www.cnblogs.com/strengthen/p/11258422.html

解法1:kruskal算法

kruskal算法核心思想:
1)初始阶段,每个点互不相识,各自为一个孤岛。
2)以题设给定的“边”为入手,不断的通过整合边所连接两个点,让所有孤岛都连接到一起。
3)利用贪心算法,选择cost小的边为起点,遍历所有的边。
4)遍历的过程中,如果发现当前边所在的两个点在两个孤岛上,则将他们合并。这一步采用的并查集方法(即为不同的集合寻找father,father相同的节点,为同一个集合)。
思想还是比较清晰和简洁,我没有去证明为什么第三步用贪心算法一定是可以的。。有兴趣的可以查阅资料再证明一下。

import java.util.LinkedList;
import java.util.List;

public class MinimumCost {
    static class Node{
        int left;
        int right;
        int val;

        public Node(int row, int col,  int val) {
            this.left = row;
            this.right = col;
            this.val = val;
        }
    }
    static class UnionFind {
       private int[] parent;
       private int count;

       public UnionFind(int count) {
           this.count = count;
           this.parent = new int[count];
           for(int i=0; i<count; ++i){
               parent[i] = i;
           }
       }
       public int find (int index) {
           if (parent[index] == index) {
               return index;
           }else {
               return find(parent[index]);
           }
       }
       public int union(Node node) {
           int index1Root = find(node.left);
           int index2Root = find(node.right);
           if (index1Root != index2Root) {
               parent[index1Root] = index2Root;
               return node.val;
           }
           return 0;
       }
    }

    public static int minimumCost(int N, int[][] connections) {
        int row = connections.length;
        List<Node> heap = new LinkedList<Node>();

        for(int i=0; i< row; ++i){
            heap.add(new Node(connections[i][0], connections[i][1], connections[i][2]));
        }
        heap.sort((node1, node2)->(node1.val- node2.val));
        UnionFind unionFind = new UnionFind(N+1);

        int cost =0;
        for(int i=0; i< heap.size(); ++i){
            Node node = heap.get(i);
            cost+=unionFind.union(node);
        }
        for(int i=2; i<= N; ++i){
            if (unionFind.find(i) != unionFind.find(i-1)) {
                return -1;
            }
        }

        return cost;
    }

    public static void main(String[] args) {
        int N = 4;
        int[][] conections = {{1,2,5},{1,3,6},{2,3,1}, {2,4,10},{1,4,1}};

        System.out.println(minimumCost(N, conections));
    }
}


    static class UnionFind {
        private int[] parent;
        private int count;

        public UnionFind(int count) {
            this.count = count;
            parent = new int[count];
            for (int i=0; i<count; i++) {
                parent[i] = i;
            }
        }
        public int find(int index) {
            if (parent[index] == index) {
                return index;
            } else {
                return find(parent[index]);
            }
        }
        public boolean union(int index1, int index2) {
            int roota = find(index1);
            int rootb = find(index2);
            if (roota != rootb) {
                parent[roota] = rootb;
                return true;
            }
            return false;
        }
    }

    public static int minimumCost(int N, int[][] connections) {
        Arrays.sort(connections, (o1,o2)->(o1[2]-o2[2]));
        UnionFind unionFind = new UnionFind(N+1);
        int cost = 0;
        for (int i=0; i<connections.length; ++i) {
            Boolean isUnion = unionFind.union(connections[i][0], connections[i][1]);
            if (isUnion) {
                cost += connections[i][2];
            }
        }
        for (int i=2; i<=N; ++i) {
            if (unionFind.find(i) != unionFind.find(i-1)) {
                return -1;
            }
        }
        return cost;
    }

    public static void main(String[] args) {
        int N = 4;
        int[][] connections =  {{1,2,3},{3,4,4},{1,3,20},{2,4,6},{1,4,2}};

        System.out.println(minimumCost(N, connections));
    }

 



 

 
posted on 2021-10-21 14:10  yuluoxingkong  阅读(71)  评论(0编辑  收藏  举报