链接: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题)的更多相关文章

  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. 如何从Word带图粘贴到编辑器中

    这种方法是servlet,编写好在web.xml里配置servlet-class和servlet-mapping即可使用 后台(服务端)java服务代码:(上传至ROOT/lqxcPics文件夹下) ...

  2. pytest相关问题解析

    1. 如果你想查询在你的环境下有哪些pytest的active plugin可以使用: py.test --traceconfig 会得到一个扩展的头文件名显示激活的插件和他们的名字.同时也会打印出当 ...

  3. 631D Messenger

    题目大意 给你串s和t 但是每个串都被表示为多个二元组(x,y)表示字符x连续出现y次 问t在s中出现了多少次 分析 我们先将s和t每个串中二元组合并 即相邻两个二元组如果字符相等则将它们变为一个 特 ...

  4. maven 依赖调解

    项目A有两条依赖关系  A->B->C->X(1.0),A->D->X(2.0) ,X是A的传递性依赖,但是两条路径上有两个版本的依赖,会选择哪个呢? maven 依赖调 ...

  5. 使用 GitLab 的 OAuth2 认证服务

    原文地址 本文档讲述如何使用 GitLab 作为 OAuth 认证服务提供商,以通过 GitLab 的 OAuth 认证登录其他服务(例如持续集成工具 Drone). 如果想使用其他 OAuth 身份 ...

  6. Win7 VSCode 在线安装Rust语言及环境配置

    睡前彻底解决在VSCode中,按F12不跳转到标准库源码的问题. 首先,如果装过离线版,卸载掉. 然后去官网下载 rustup-init.exe https://www.rust-lang.org/t ...

  7. ruby基本语法(2)

    关于数组 Ruby数组中的数据类型可以不相同并且长度也是可变的.(好聪明啊感觉用的久了就会变笨了,除非你本来就是老手)比如下面的例子 Myarray=[1,2,“ruby”] Ruby也支持那种-1的 ...

  8. 结合Pool进程池进程,实现进程之间的通讯,稍微复杂的运用

    #进程池中的Queue """ 如果要用Pool创建进程,就需要multiprocessing.Manager()中的Queue() 而不是multiprocessing ...

  9. Yaconf – 一个高性能的配置管理扩展

    鸟哥出品:http://www.laruence.com/2015/06/12/3051.html 首先说说, 这个是干啥的. 我见过很多的项目中, 用PHP文件做配置的, 一个config目录下可能 ...

  10. jQuery基础--插件

    1. 插件 1.1. 常用插件 插件:jquery不可能包含所有的功能,我们可以通过插件扩展jquery的功能. jQuery有着丰富的插件,使用这些插件能给jQuery提供一些额外的功能. 1.1. ...