链接:https://leetcode.com/tag/union-find/

【128】Longest Consecutive Sequence  (2018年11月22日,开始解决hard题)

给了一个无序的数组,问这个数组里面的元素(可以重新排序)能组成的最长的连续子序列是多长。本题的时间复杂度要求是 O(N).

本题 array 专题里面有, 链接:https://www.cnblogs.com/zhangwanying/p/9610923.html ,用个 hashmap 可以做到 O(N).

本题用 union-find 怎么解,不知道 orz。

【130】Surrounded Regions (2019年1月31日,UF专题)

给了个二维 grid,把里面 O 全部变成 X,但是 边界和边界联通区域内的 O 保留。

题解:我以前是用dfs解的。今天看了discuss高票使用UF,学习了一下。我们把边界上的 O 和边界联通区域内的 O 的坐标与一个 dummy node 联通就好了。然后遍历 grid,如果坐标与 dummy node 坐标联通,就保留成 O,不然改成 X

  1. class UF {
  2. public:
  3. UF(int size) {
  4. father.resize(size);
  5. rank.resize(size, );
  6. for (int i = ; i < size; ++i) {
  7. father[i] = i;
  8. }
  9. }
  10. int find(int x) {
  11. return x == father[x] ? x : father[x] = find(father[x]);
  12. }
  13. void connect(int x, int y) {
  14. int xx = find(x), yy = find(y);
  15. if (xx == yy) { return; }
  16. if (yy > xx) {
  17. father[xx] = yy;
  18. } else {
  19. father[yy] = x;
  20. }
  21. }
  22. vector<int> father;
  23. vector<int> rank;
  24. };
  25. class Solution {
  26. public:
  27. void solve(vector<vector<char>>& board) {
  28. if (board.empty() || board[].empty()) { return; }
  29. const int n = board.size(), m = board[].size();
  30. UF uf(n * m + );
  31. for (int i = ; i < n; ++i) {
  32. for (int j = ; j < m; ++j) {
  33. if (board[i][j] == 'O') {
  34. if ((i == || i == n- || j == || j == m-)) {
  35. uf.connect(i * m + j, n * m);
  36. } else {
  37. if (board[i-][j] == 'O') {
  38. uf.connect(i * m + j, (i-) * m + j);
  39. }
  40. if (board[i+][j] == 'O') {
  41. uf.connect(i * m + j, (i+) * m + j);
  42. }
  43. if (board[i][j-] == 'O') {
  44. uf.connect(i * m + j, i * m + j - );
  45. }
  46. if (board[i][j+] == 'O') {
  47. uf.connect(i * m + j, i * m + j + );
  48. }
  49. }
  50. }
  51. }
  52. }
  53. for (int i = ; i < n; ++i) {
  54. for (int j = ; j < m; ++j) {
  55. if (uf.find(i * m +j) != n * m) {
  56. board[i][j] = 'X';
  57. }
  58. }
  59. }
  60. return;
  61. }
  62. };

【200】Number of Islands  (2019年1月31日,UF专题)

给了一个二维的grid,0 代表海, 1 的联通块代表岛屿,问有多少岛屿。

题解:和130题一样的想法。判断当前结点和上下左右四个结点是不是都是1,如果是的话,就联通这两个点。

  1. class UF {
  2. public:
  3. UF(int size) {
  4. father.resize(size);
  5. rank.resize(size, );
  6. for (int i = ; i < size; ++i) {
  7. father[i] = i;
  8. }
  9. }
  10. int find(int x) {
  11. return x == father[x] ? x : father[x] = find(father[x]);
  12. }
  13. void connect(int x, int y) {
  14. int xx = find(x), yy = find(y);
  15. if (xx == yy) { return; }
  16. if (yy < xx) {
  17. father[xx] = yy;
  18. } else {
  19. father[yy] = xx;
  20. }
  21. }
  22. vector<int> father;
  23. vector<int> rank;
  24. };
  25. class Solution {
  26. public:
  27. int numIslands(vector<vector<char>>& grid) {
  28. if (grid.size() == || grid[].size() == ) {
  29. return ;
  30. }
  31. const int n = grid.size(), m = grid[].size();
  32. UF uf(n * m);
  33. for (int i = ; i < n; ++i) {
  34. for (int j = ; j < m; ++j) {
  35. int index = i * m + j;
  36. if (grid[i][j] == '') {
  37. if (i - >= && grid[i-][j] == '') {
  38. uf.connect(index, (i-) * m + j);
  39. }
  40. if (i + < n && grid[i+][j] == '') {
  41. uf.connect(index, (i+) * m + j);
  42. }
  43. if (j - >= && grid[i][j-] == '') {
  44. uf.connect(index, i * m + j - );
  45. }
  46. if (j + < m && grid[i][j+] == '') {
  47. uf.connect(index, i * m + j + );
  48. }
  49. }
  50. }
  51. }
  52. int ret = ;
  53. for (int i = ; i < n; ++i) {
  54. for (int j = ; j < m; ++j) {
  55. int index = i * m + j;
  56. if (grid[i][j] == '' && uf.find(index) == index) {
  57. ret++;
  58. }
  59. }
  60. }
  61. return ret;
  62. }
  63. };

【261】Graph Valid Tree (2019年1月31日,UF专题)

给了 N 个结点 和 一个边的集合,问这个边的集合能不能构成一棵树。

题解:先检查 边集合大小是否等于 N-1, 然后用并查集检查是否有环,没有的话,就是树。

  1. class UF {
  2. public:
  3. UF(int size) {
  4. father.resize(size);
  5. for (int i = ; i < size; ++i) {
  6. father[i] = i;
  7. }
  8. }
  9. int find (int x) {
  10. return x == father[x] ? x : father[x] = find(father[x]);
  11. }
  12. void connect (int x, int y) {
  13. int xx = find(x), yy = find(y);
  14. if (xx == yy) { return; }
  15. if (xx < yy) {
  16. father[yy] = xx;
  17. } else {
  18. father[xx] = yy;
  19. }
  20. }
  21. vector<int> father;
  22. };
  23. class Solution {
  24. public:
  25. bool validTree(int n, vector<pair<int, int>>& edges) {
  26. const int edgeSize = edges.size();
  27. if (edgeSize != n-) { return false; } // n 个结点的树有 n-1 条边
  28. UF uf(n);
  29. for (auto& e: edges) {
  30. int u = uf.find(e.first), v = uf.find(e.second);
  31. if (u == v) {
  32. return false;
  33. }
  34. uf.connect(e.first, e.second);
  35. }
  36. return true;
  37. }
  38. };

【305】Number of Islands II (2019年1月31日,UF专题)

【323】Number of Connected Components in an Undirected Graph (2019年2月2日,UF tag专题)

给了 n 个结点,编号从 0 到 n-1,以及一个边的集合。问这个无向图里面有多少个联通块。

题解:直接 uf 数联通块。

  1. class UF {
  2. public:
  3. UF(int size) {
  4. father.resize(size);
  5. for (int i = ; i < size; ++i) {
  6. father[i] = i;
  7. }
  8. }
  9. int find(int x) {
  10. return x == father[x] ? x : father[x] = find(father[x]);
  11. }
  12. void connect(int x, int y) {
  13. int xx = find(x), yy = find(y);
  14. if (xx == yy) { return; }
  15. if (yy < xx) {
  16. father[xx] = yy;
  17. } else {
  18. father[yy] = xx;
  19. }
  20. }
  21. int getCount() {
  22. int count = ;
  23. for (int i = ; i < father.size(); ++i) {
  24. if (father[i] == i) {
  25. count++;
  26. }
  27. }
  28. return count;
  29. }
  30. vector<int> father;
  31. };
  32. class Solution {
  33. public:
  34. int countComponents(int n, vector<pair<int, int>>& edges) {
  35. UF uf(n);
  36. for (auto& e : edges) {
  37. int u = e.first, v = e.second;
  38. uf.connect(u, v);
  39. }
  40. return uf.getCount();
  41. }
  42. };

【547】Friend Circles (2019年2月2日,UF tag专题)

给了一个邻接矩阵, M[i][j]  = 1代表 i,j 是朋友关系,我们算上间接朋友关系,问这个矩阵里面一共有几个朋友圈子?

题解:直接用 uf 数这个图里面有多少联通块。

  1. class UF {
  2. public:
  3. UF(int size) {
  4. father.resize(size);
  5. for (int i = ; i < size; ++i) {
  6. father[i] = i;
  7. }
  8. }
  9. int find(int x) {
  10. return x == father[x] ? x : father[x] = find(father[x]);
  11. }
  12. void connect(int x, int y) {
  13. int xx = find(x), yy = find(y);
  14. if (xx == yy) { return; }
  15. if (yy < xx) {
  16. father[xx] = yy;
  17. } else {
  18. father[yy] = xx;
  19. }
  20. }
  21. vector<int> father;
  22. };
  23. class Solution {
  24. public:
  25. int findCircleNum(vector<vector<int>>& M) {
  26. const int n = M.size();
  27. UF uf(n);
  28. for (int i = ; i < n; ++i) {
  29. for (int j = ; j < n; ++j) {
  30. if (M[i][j] == ) {
  31. uf.connect(i, j);
  32. }
  33. }
  34. }
  35. int ret = ;
  36. for (int i = ; i < uf.father.size(); ++i) {
  37. if (i == uf.father[i]) {
  38. ret++;
  39. }
  40. }
  41. return ret;
  42. }
  43. };

【684】Redundant Connection (2018年11月22日,contest 51 模拟赛做到了)

在本题中,树是一个无环的无向图。输入一个N个结点(编号是1~N)的图,有一条边是多余的,把这条边找出来。

  1. Example :
  2. Input: [[,], [,], [,]]
  3. Output: [,]
  4. Explanation: The given undirected graph will be like this:
  5. / \
  6. -
  7.  
  8. Example :
  9. Input: [[,], [,], [,], [,], [,]]
  10. Output: [,]
  11. Explanation: The given undirected graph will be like this:
  12. - -
  13. | |
  14. -
  15.  
  16. Note:
  17. The size of the input 2D-array will be between and .
  18. Every integer represented in the 2D-array will be between and N, where N is the size of the input array.

题解:我是用并查集解的。对于每一条边的两个结点,如果他们的爸爸不是同一个爸爸,那么就 unoin 这两个结点,如果他们两个的爸爸是同一个爸爸,就说明这条边多余了,直接返回这条边就行了。

  1. class Solution {
  2. public:
  3. int findfather(int x) {
  4. return x == father[x] ? x : findfather(father[x]);
  5. }
  6. void unionNode(int x, int y) {
  7. x = findfather(x);
  8. y = findfather(y);
  9. if (x == y) { return; }
  10. father[y] = x;
  11. }
  12.  
  13. vector<int> findRedundantConnection(vector<vector<int>>& edges) {
  14. n = edges.size();
  15. father.resize(n+); //redundant 0
  16. for (int i = ; i < n+; ++i) {
  17. father[i] = i;
  18. }
  19. vector<int> ret;
  20. for (auto e : edges) {
  21. int u = min(e[], e[]), v = max(e[], e[]);
  22. if (findfather(v) == findfather(u)) {
  23. ret = e;
  24. break;
  25. } else {
  26. unionNode(u, v);
  27. }
  28. }
  29. return ret;
  30. }
  31. int n = ;
  32. vector<int> father;
  33.  
  34. };

【685】Redundant Connection II (2019年2月2日,UF专题)(Hard)

给了 1~N,N个结点,N条边的有向图,删除一条边之后能形成一棵树,返回需要删除的那条边,如果有多个candidate,返回数组中最后那条需要删除的边。

题解:本题和上一题的不同之处在于,上一个题只是检测是否有环,这个题多了一些业务逻辑的判断,主要是一个树的一个结点不可能有两个爸爸。

如有它有两个爸爸,那么这两条边的其中之一一定是答案。

那么我们先找出来看看是否存在这种情况(一个结点有两个爸爸),parent[i] 代表 i 结点的爸爸。如果不存在这种情况,直接检测是否有环就好了。

如果存在这种情况的话,我们先删除这个结点和它第二个爸爸这条边,看剩下的边是否有环,如果有环的话,就应该返回这个结点和它第一个爸爸这条边。

  1. class UF {
  2. public:
  3. UF(int size) {
  4. father.resize(size);
  5. for (int i = ; i < size; ++i) {
  6. father[i] = i;
  7. }
  8. }
  9. int find(int x) {
  10. return x == father[x] ? x : father[x] = find(father[x]);
  11. }
  12. void connect(int x, int y) {
  13. int xx = find(x), yy = find(y);
  14. if (xx == yy) { return; }
  15. if (yy < xx) {
  16. father[xx] = yy;
  17. } else {
  18. father[yy] = xx;
  19. }
  20. }
  21. vector<int> father;
  22. };
  23. class Solution {
  24. public:
  25. vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
  26. const int n = edges.size();
  27. UF uf(n+);
  28. vector<int> parent(n+, );
  29. vector<int> ans1, ans2;
  30. for (auto& e : edges) {
  31. int p = e[], s = e[];
  32. if (parent[s] != ) {
  33. ans1 = {parent[s], s};
  34. ans2 = e;
  35. e[] = e[] = -; //先把第二条边删除,然后下面用uf检测是否有环
  36. break;
  37. } else {
  38. parent[s] = p;
  39. }
  40. }
  41. for (auto e : edges) {
  42. if (e[] < && e[] < ) { continue; }
  43. int u = uf.find(e[]), v = uf.find(e[]);
  44. if (u == v) { //如果说在删除第二条边的情况下,有环,如果有第一条边,就返回第一条边,不然返回第二条边
  45. if (!ans1.empty()) {return ans1;}
  46. return e;
  47. }
  48. uf.connect(e[], e[]);
  49. }
  50. return ans2;
  51. }
  52. };

【721】Accounts Merge

【737】Sentence Similarity II

【765】Couples Holding Hands

【778】Swim in Rising Water

【803】Bricks Falling When Hit

【839】Similar String Groups

【928】Minimize Malware Spread II

【LeetCode】并查集 union-find(共16题)的更多相关文章

  1. [leetcode] 并查集(Ⅰ)

    预备知识 并查集 (Union Set) 一种常见的应用是计算一个图中连通分量的个数.比如: a e / \ | b c f | | d g 上图的连通分量的个数为 2 . 并查集的主要思想是在每个连 ...

  2. 并查集(Union/Find)模板及详解

    概念: 并查集是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子图.求最小生成树的Kruskal 算法和求最近公共祖先等. 操作: 并查集的基本操作有两个 ...

  3. POJ 1611 The Suspects 并查集 Union Find

    本题也是个标准的并查集题解. 操作完并查集之后,就是要找和0节点在同一个集合的元素有多少. 注意这个操作,须要先找到0的父母节点.然后查找有多少个节点的额父母节点和0的父母节点同样. 这个时候须要对每 ...

  4. [leetcode] 并查集(Ⅱ)

    最长连续序列 题目[128]:链接. 解题思路 节点本身的值作为节点的标号,两节点相邻,即允许合并(x, y)的条件为x == y+1 . 因为数组中可能会出现值为 -1 的节点,因此不能把 root ...

  5. [leetcode] 并查集(Ⅲ)

    婴儿名字 题目[Interview-1707]:典型并查集题目. 解题思路 首先对 names 这种傻 X 字符串结构进行预处理,转换为一个 map,key 是名字,val 是名字出现的次数. 然后是 ...

  6. 一道并查集的(坑)题:关闭农场closing the farm

    题目描述 in English: Farmer John and his cows are planning to leave town for a long vacation, and so FJ ...

  7. 石头剪刀布(2019Wannafly winter camp day3 i) 带权并查集+按秩合并 好题

    题目传送门 思路: 按照题意描述,所有y挑战x的关系最后会形成一棵树的结构,n个人的总方案数是 3n 种,假设一个人被挑战(主场作战)a次,挑战别人(客场)b次,那么这个人存活到最后的方案数就是3n* ...

  8. Java 并查集Union Find

    对于一组数据,主要支持两种动作: union isConnected public interface UF { int getSize(); boolean isConnected(int p,in ...

  9. Marriage Match II(二分+并查集+最大流,好题)

    Marriage Match II http://acm.hdu.edu.cn/showproblem.php?pid=3081 Time Limit: 2000/1000 MS (Java/Othe ...

随机推荐

  1. Prometheus + Node Exporter + Grafana 监控主机运行信息

      上一篇文章中讲了如何利用Prometheus和Grafana监控SpringBoot应用的JVM信息,这次就来看看如何监控 服务器运行状态,先列出用到的工具: Prometheus node_ex ...

  2. postman接口自动化测试之如何使用)

    postman 是一款强大网页调试工具的客户端,postman为用户提供强大的 Web API & HTTP 请求调试功能.postman能够发送任何类型的HTTP 请求 (GET, HEAD ...

  3. (转)pycharm autopep8配置

    转:https://blog.csdn.net/BobYuan888/article/details/81943808 1.pip下载安装: 在命令行下输入以下命令安装autopep8 pip ins ...

  4. 黑马lavarel教程---2、获取用户输入

    黑马lavarel教程---2.获取用户输入 一.总结 一句话总结: lavarel中获取用户输入可以通过Input外观模式和Request外观模式,两者的对应的方法啥的都一样,比如get.all.o ...

  5. Windows命令学习

    总: 1.window dos命令不区分大小写  2.指令参数 /a   -a 等价 更倾向于 / 3.命令有疑问: CMD输入help 或者单条命令 /? help time /? 用到的实用命令总 ...

  6. Ubuntu安装byzanz截取动态效果图

    byzanz-record主要参数选项 用法: byzanz-record [选项...] 录制您的当前桌面会话 帮助选项: -?, --help 显示帮助选项 --help-all 显示全部帮助选项 ...

  7. python中函数的嵌套和作用域链

    1.三元运算if条件成立的结果 if 条件 else 条件不成立的结果例如: a=20 b=10 c=a if a>b else b print(c) 2.命名空间 全局命名空间:创建的存储“变 ...

  8. PHPer面试指南-laravel 篇

    简述 Laravel 的生命周期 Laravel 采用了单一入口模式,应用的所有请求入口都是 public/index.php 文件. 注册类文件自动加载器 : Laravel通过 composer ...

  9. Python入门习题3.天天向上

    例3.1 一年365天,以第一天的能力值为基数,记为1.0,当好好学习时能力值相比前一天提高1%,当没有学习时能力值相比前一天下降1%.每天努力(dayup)和每天放任(daydown),一年下来的能 ...

  10. 洛谷 P3374 【模板】树状数组 1(单点加,区间和)

    题目链接 https://www.luogu.org/problemnew/show/P3374 树状数组 树状数组最基本的就是求区间和. 维护: 空间复杂度:O(n) 时间复杂度(区间和,单点修改) ...