【LeetCode】并查集 union-find(共16题)
链接: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
- class UF {
- public:
- UF(int size) {
- father.resize(size);
- rank.resize(size, );
- for (int i = ; i < size; ++i) {
- father[i] = i;
- }
- }
- int find(int x) {
- return x == father[x] ? x : father[x] = find(father[x]);
- }
- void connect(int x, int y) {
- int xx = find(x), yy = find(y);
- if (xx == yy) { return; }
- if (yy > xx) {
- father[xx] = yy;
- } else {
- father[yy] = x;
- }
- }
- vector<int> father;
- vector<int> rank;
- };
- class Solution {
- public:
- void solve(vector<vector<char>>& board) {
- if (board.empty() || board[].empty()) { return; }
- const int n = board.size(), m = board[].size();
- UF uf(n * m + );
- for (int i = ; i < n; ++i) {
- for (int j = ; j < m; ++j) {
- if (board[i][j] == 'O') {
- if ((i == || i == n- || j == || j == m-)) {
- uf.connect(i * m + j, n * m);
- } else {
- if (board[i-][j] == 'O') {
- uf.connect(i * m + j, (i-) * m + j);
- }
- if (board[i+][j] == 'O') {
- uf.connect(i * m + j, (i+) * m + j);
- }
- if (board[i][j-] == 'O') {
- uf.connect(i * m + j, i * m + j - );
- }
- if (board[i][j+] == 'O') {
- uf.connect(i * m + j, i * m + j + );
- }
- }
- }
- }
- }
- for (int i = ; i < n; ++i) {
- for (int j = ; j < m; ++j) {
- if (uf.find(i * m +j) != n * m) {
- board[i][j] = 'X';
- }
- }
- }
- return;
- }
- };
【200】Number of Islands (2019年1月31日,UF专题)
给了一个二维的grid,0 代表海, 1 的联通块代表岛屿,问有多少岛屿。
题解:和130题一样的想法。判断当前结点和上下左右四个结点是不是都是1,如果是的话,就联通这两个点。
- class UF {
- public:
- UF(int size) {
- father.resize(size);
- rank.resize(size, );
- for (int i = ; i < size; ++i) {
- father[i] = i;
- }
- }
- int find(int x) {
- return x == father[x] ? x : father[x] = find(father[x]);
- }
- void connect(int x, int y) {
- int xx = find(x), yy = find(y);
- if (xx == yy) { return; }
- if (yy < xx) {
- father[xx] = yy;
- } else {
- father[yy] = xx;
- }
- }
- vector<int> father;
- vector<int> rank;
- };
- class Solution {
- public:
- int numIslands(vector<vector<char>>& grid) {
- if (grid.size() == || grid[].size() == ) {
- return ;
- }
- const int n = grid.size(), m = grid[].size();
- UF uf(n * m);
- for (int i = ; i < n; ++i) {
- for (int j = ; j < m; ++j) {
- int index = i * m + j;
- if (grid[i][j] == '') {
- if (i - >= && grid[i-][j] == '') {
- uf.connect(index, (i-) * m + j);
- }
- if (i + < n && grid[i+][j] == '') {
- uf.connect(index, (i+) * m + j);
- }
- if (j - >= && grid[i][j-] == '') {
- uf.connect(index, i * m + j - );
- }
- if (j + < m && grid[i][j+] == '') {
- uf.connect(index, i * m + j + );
- }
- }
- }
- }
- int ret = ;
- for (int i = ; i < n; ++i) {
- for (int j = ; j < m; ++j) {
- int index = i * m + j;
- if (grid[i][j] == '' && uf.find(index) == index) {
- ret++;
- }
- }
- }
- return ret;
- }
- };
【261】Graph Valid Tree (2019年1月31日,UF专题)
给了 N 个结点 和 一个边的集合,问这个边的集合能不能构成一棵树。
题解:先检查 边集合大小是否等于 N-1, 然后用并查集检查是否有环,没有的话,就是树。
- class UF {
- public:
- UF(int size) {
- father.resize(size);
- for (int i = ; i < size; ++i) {
- father[i] = i;
- }
- }
- int find (int x) {
- return x == father[x] ? x : father[x] = find(father[x]);
- }
- void connect (int x, int y) {
- int xx = find(x), yy = find(y);
- if (xx == yy) { return; }
- if (xx < yy) {
- father[yy] = xx;
- } else {
- father[xx] = yy;
- }
- }
- vector<int> father;
- };
- class Solution {
- public:
- bool validTree(int n, vector<pair<int, int>>& edges) {
- const int edgeSize = edges.size();
- if (edgeSize != n-) { return false; } // n 个结点的树有 n-1 条边
- UF uf(n);
- for (auto& e: edges) {
- int u = uf.find(e.first), v = uf.find(e.second);
- if (u == v) {
- return false;
- }
- uf.connect(e.first, e.second);
- }
- return true;
- }
- };
【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 数联通块。
- class UF {
- public:
- UF(int size) {
- father.resize(size);
- for (int i = ; i < size; ++i) {
- father[i] = i;
- }
- }
- int find(int x) {
- return x == father[x] ? x : father[x] = find(father[x]);
- }
- void connect(int x, int y) {
- int xx = find(x), yy = find(y);
- if (xx == yy) { return; }
- if (yy < xx) {
- father[xx] = yy;
- } else {
- father[yy] = xx;
- }
- }
- int getCount() {
- int count = ;
- for (int i = ; i < father.size(); ++i) {
- if (father[i] == i) {
- count++;
- }
- }
- return count;
- }
- vector<int> father;
- };
- class Solution {
- public:
- int countComponents(int n, vector<pair<int, int>>& edges) {
- UF uf(n);
- for (auto& e : edges) {
- int u = e.first, v = e.second;
- uf.connect(u, v);
- }
- return uf.getCount();
- }
- };
【547】Friend Circles (2019年2月2日,UF tag专题)
给了一个邻接矩阵, M[i][j] = 1代表 i,j 是朋友关系,我们算上间接朋友关系,问这个矩阵里面一共有几个朋友圈子?
题解:直接用 uf 数这个图里面有多少联通块。
- class UF {
- public:
- UF(int size) {
- father.resize(size);
- for (int i = ; i < size; ++i) {
- father[i] = i;
- }
- }
- int find(int x) {
- return x == father[x] ? x : father[x] = find(father[x]);
- }
- void connect(int x, int y) {
- int xx = find(x), yy = find(y);
- if (xx == yy) { return; }
- if (yy < xx) {
- father[xx] = yy;
- } else {
- father[yy] = xx;
- }
- }
- vector<int> father;
- };
- class Solution {
- public:
- int findCircleNum(vector<vector<int>>& M) {
- const int n = M.size();
- UF uf(n);
- for (int i = ; i < n; ++i) {
- for (int j = ; j < n; ++j) {
- if (M[i][j] == ) {
- uf.connect(i, j);
- }
- }
- }
- int ret = ;
- for (int i = ; i < uf.father.size(); ++i) {
- if (i == uf.father[i]) {
- ret++;
- }
- }
- return ret;
- }
- };
【684】Redundant Connection (2018年11月22日,contest 51 模拟赛做到了)
在本题中,树是一个无环的无向图。输入一个N个结点(编号是1~N)的图,有一条边是多余的,把这条边找出来。
- Example :
- Input: [[,], [,], [,]]
- Output: [,]
- Explanation: The given undirected graph will be like this:
- / \
- -
- Example :
- Input: [[,], [,], [,], [,], [,]]
- Output: [,]
- Explanation: The given undirected graph will be like this:
- - -
- | |
- -
- Note:
- The size of the input 2D-array will be between and .
- Every integer represented in the 2D-array will be between and N, where N is the size of the input array.
题解:我是用并查集解的。对于每一条边的两个结点,如果他们的爸爸不是同一个爸爸,那么就 unoin 这两个结点,如果他们两个的爸爸是同一个爸爸,就说明这条边多余了,直接返回这条边就行了。
- class Solution {
- public:
- int findfather(int x) {
- return x == father[x] ? x : findfather(father[x]);
- }
- void unionNode(int x, int y) {
- x = findfather(x);
- y = findfather(y);
- if (x == y) { return; }
- father[y] = x;
- }
- vector<int> findRedundantConnection(vector<vector<int>>& edges) {
- n = edges.size();
- father.resize(n+); //redundant 0
- for (int i = ; i < n+; ++i) {
- father[i] = i;
- }
- vector<int> ret;
- for (auto e : edges) {
- int u = min(e[], e[]), v = max(e[], e[]);
- if (findfather(v) == findfather(u)) {
- ret = e;
- break;
- } else {
- unionNode(u, v);
- }
- }
- return ret;
- }
- int n = ;
- vector<int> father;
- };
【685】Redundant Connection II (2019年2月2日,UF专题)(Hard)
给了 1~N,N个结点,N条边的有向图,删除一条边之后能形成一棵树,返回需要删除的那条边,如果有多个candidate,返回数组中最后那条需要删除的边。
题解:本题和上一题的不同之处在于,上一个题只是检测是否有环,这个题多了一些业务逻辑的判断,主要是一个树的一个结点不可能有两个爸爸。
如有它有两个爸爸,那么这两条边的其中之一一定是答案。
那么我们先找出来看看是否存在这种情况(一个结点有两个爸爸),parent[i] 代表 i 结点的爸爸。如果不存在这种情况,直接检测是否有环就好了。
如果存在这种情况的话,我们先删除这个结点和它第二个爸爸这条边,看剩下的边是否有环,如果有环的话,就应该返回这个结点和它第一个爸爸这条边。
- class UF {
- public:
- UF(int size) {
- father.resize(size);
- for (int i = ; i < size; ++i) {
- father[i] = i;
- }
- }
- int find(int x) {
- return x == father[x] ? x : father[x] = find(father[x]);
- }
- void connect(int x, int y) {
- int xx = find(x), yy = find(y);
- if (xx == yy) { return; }
- if (yy < xx) {
- father[xx] = yy;
- } else {
- father[yy] = xx;
- }
- }
- vector<int> father;
- };
- class Solution {
- public:
- vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
- const int n = edges.size();
- UF uf(n+);
- vector<int> parent(n+, );
- vector<int> ans1, ans2;
- for (auto& e : edges) {
- int p = e[], s = e[];
- if (parent[s] != ) {
- ans1 = {parent[s], s};
- ans2 = e;
- e[] = e[] = -; //先把第二条边删除,然后下面用uf检测是否有环
- break;
- } else {
- parent[s] = p;
- }
- }
- for (auto e : edges) {
- if (e[] < && e[] < ) { continue; }
- int u = uf.find(e[]), v = uf.find(e[]);
- if (u == v) { //如果说在删除第二条边的情况下,有环,如果有第一条边,就返回第一条边,不然返回第二条边
- if (!ans1.empty()) {return ans1;}
- return e;
- }
- uf.connect(e[], e[]);
- }
- return ans2;
- }
- };
【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题)的更多相关文章
- [leetcode] 并查集(Ⅰ)
预备知识 并查集 (Union Set) 一种常见的应用是计算一个图中连通分量的个数.比如: a e / \ | b c f | | d g 上图的连通分量的个数为 2 . 并查集的主要思想是在每个连 ...
- 并查集(Union/Find)模板及详解
概念: 并查集是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子图.求最小生成树的Kruskal 算法和求最近公共祖先等. 操作: 并查集的基本操作有两个 ...
- POJ 1611 The Suspects 并查集 Union Find
本题也是个标准的并查集题解. 操作完并查集之后,就是要找和0节点在同一个集合的元素有多少. 注意这个操作,须要先找到0的父母节点.然后查找有多少个节点的额父母节点和0的父母节点同样. 这个时候须要对每 ...
- [leetcode] 并查集(Ⅱ)
最长连续序列 题目[128]:链接. 解题思路 节点本身的值作为节点的标号,两节点相邻,即允许合并(x, y)的条件为x == y+1 . 因为数组中可能会出现值为 -1 的节点,因此不能把 root ...
- [leetcode] 并查集(Ⅲ)
婴儿名字 题目[Interview-1707]:典型并查集题目. 解题思路 首先对 names 这种傻 X 字符串结构进行预处理,转换为一个 map,key 是名字,val 是名字出现的次数. 然后是 ...
- 一道并查集的(坑)题:关闭农场closing the farm
题目描述 in English: Farmer John and his cows are planning to leave town for a long vacation, and so FJ ...
- 石头剪刀布(2019Wannafly winter camp day3 i) 带权并查集+按秩合并 好题
题目传送门 思路: 按照题意描述,所有y挑战x的关系最后会形成一棵树的结构,n个人的总方案数是 3n 种,假设一个人被挑战(主场作战)a次,挑战别人(客场)b次,那么这个人存活到最后的方案数就是3n* ...
- Java 并查集Union Find
对于一组数据,主要支持两种动作: union isConnected public interface UF { int getSize(); boolean isConnected(int p,in ...
- Marriage Match II(二分+并查集+最大流,好题)
Marriage Match II http://acm.hdu.edu.cn/showproblem.php?pid=3081 Time Limit: 2000/1000 MS (Java/Othe ...
随机推荐
- Prometheus + Node Exporter + Grafana 监控主机运行信息
上一篇文章中讲了如何利用Prometheus和Grafana监控SpringBoot应用的JVM信息,这次就来看看如何监控 服务器运行状态,先列出用到的工具: Prometheus node_ex ...
- postman接口自动化测试之如何使用)
postman 是一款强大网页调试工具的客户端,postman为用户提供强大的 Web API & HTTP 请求调试功能.postman能够发送任何类型的HTTP 请求 (GET, HEAD ...
- (转)pycharm autopep8配置
转:https://blog.csdn.net/BobYuan888/article/details/81943808 1.pip下载安装: 在命令行下输入以下命令安装autopep8 pip ins ...
- 黑马lavarel教程---2、获取用户输入
黑马lavarel教程---2.获取用户输入 一.总结 一句话总结: lavarel中获取用户输入可以通过Input外观模式和Request外观模式,两者的对应的方法啥的都一样,比如get.all.o ...
- Windows命令学习
总: 1.window dos命令不区分大小写 2.指令参数 /a -a 等价 更倾向于 / 3.命令有疑问: CMD输入help 或者单条命令 /? help time /? 用到的实用命令总 ...
- Ubuntu安装byzanz截取动态效果图
byzanz-record主要参数选项 用法: byzanz-record [选项...] 录制您的当前桌面会话 帮助选项: -?, --help 显示帮助选项 --help-all 显示全部帮助选项 ...
- python中函数的嵌套和作用域链
1.三元运算if条件成立的结果 if 条件 else 条件不成立的结果例如: a=20 b=10 c=a if a>b else b print(c) 2.命名空间 全局命名空间:创建的存储“变 ...
- PHPer面试指南-laravel 篇
简述 Laravel 的生命周期 Laravel 采用了单一入口模式,应用的所有请求入口都是 public/index.php 文件. 注册类文件自动加载器 : Laravel通过 composer ...
- Python入门习题3.天天向上
例3.1 一年365天,以第一天的能力值为基数,记为1.0,当好好学习时能力值相比前一天提高1%,当没有学习时能力值相比前一天下降1%.每天努力(dayup)和每天放任(daydown),一年下来的能 ...
- 洛谷 P3374 【模板】树状数组 1(单点加,区间和)
题目链接 https://www.luogu.org/problemnew/show/P3374 树状数组 树状数组最基本的就是求区间和. 维护: 空间复杂度:O(n) 时间复杂度(区间和,单点修改) ...