并查集
昨天,2021年1月11号的leetcode每日一题中,用到了并查集这个数据结构。
1202. 交换字符串中的元素
在看到这道题的时候,想到了要用一个数据结构去表示字符串s中的各个下标的连通性,然后将下标连通性一致的元素排序即可。
看了题解之后知道了有一个可以表示各个元素连通性的数据结构叫并查集,所以查了些资料,自己记录一下这个数据结构。
并查集可以给一个数据结构中的元素分组,然后通过查询可以知道想要寻找的元素属于哪一个分组,并查集一般支持两种操作:
1.查询:查询就是查询你想要查询的那个元素目前属于那个分组
2.合并:合并就是将两个不同组的元素合并成同一个组的元素
而并查集当中给元素分组的方式是给每一个元素找一个父元素。当并查集初始化的时候,每一个元素的父元素都是自己,例如:
void Init()
{
for(int i=0;i<len;i++)
{
father[i]=i;
}
}
father数组代表下标为i的元素的父元素,也就是这个元素所属的组别。
当我们要合并两个元素的时候,我们可以这样
void merge(int a,int b)
{
int fa=father[a];
int fb=father[b];
if(fa!=fb)
{
father[fb]=fa;
}
}
这段代码是传入两个元素下标,当这两个元素的父元素不同,也就是他们的组别不同的时候,将b元素的父元素的父元素(有点绕口),设置为a的父元素,这样只要我们追溯每一个元素下标的父元素,我们就可以知道这这两个元素是不是属于同一个组了。
当我们要查找元素属于哪个组的时候的时候,我们可以这样
void find(int x)
{
if(father[x]==x)
return x;
else
return find(father[x]);
}
这段代码的意思就是,如果当前元素的父元素是他本身,说明他是他所在组的根节点,那么直接返回他自己的下标即可。当当前元素的父元素不是他本身的时候,我们再去找他的父元素的父元素,直到找到他的根元素为止。
并查集的简单说明总结到此,关于并查集的图文并茂的解析,还有并查集的路径压缩和按秩合并可以看这篇知乎上的文章算法学习笔记(1) : 并查集
接下来贴上自己初步写成的1202. 交换字符串中的元素的题解代码作为记录:
class Union_find
{
public:
Union_find(int n)
{
father.resize(n);
for (int i = 0;i < n;i++)
father[i] = i;
}
vector<int> father;
int find(int x)
{
if (father[x] == x)
return x;
else
return father[x] = find(father[x]);
}
void merge(int x, int y) {
x = find(x);
y = find(y);
if (x != y) {
father[y] = x;
}
}
};
class Solution {
public:
string smallestStringWithSwaps(string s, vector<vector<int>>& pairs) {
Union_find uf(s.size());
for (int i = 0;i < pairs.size();i++)
{
uf.merge(pairs[i][0], pairs[i][1]);
}
map<int, vector<int>> _map;
for (int i = 0;i < s.size();i++)
{
auto iter = _map.find(uf.find(i));
if (iter != _map.end())
{
iter->second.push_back(i);
}
else
{
vector<int> newv;
newv.push_back(i);
_map.insert(pair<int, vector<int>>(uf.find(i), newv));
}
}
for (auto iter : _map)
{
vector<int> tempv;
sort(iter.second.begin(), iter.second.end());
for (int i : iter.second)
tempv.push_back(s[i]);
sort(tempv.begin(), tempv.end());
for (int i = 0;i < iter.second.size();i++)
s[iter.second[i]] = tempv[i];
}
return s;
}
};