并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中。其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。
class Solution {
class UnionFind{
int[] parent;
int[] size;
int n;
int setCount;
public UnionFind(int n){
parent = new int[n];
for(int i = 0;i<n;i++){
parent[i]=i;
}
size = new int[n];
Arrays.fill(size,1);
this.n=n;
setCount=n;
}
public int findset(int x){
return parent[x] == x?x:(parent[x]=findset(parent[x]));
}
public void unite(int x,int y){
//确保y的 size 小
if(size[x]<size[y]){
int temp = x;
x = y;
y=temp;
}
parent[y]=x;
size[x]+=size[y];
--setCount;
}
public boolean findAndUnite(int x,int y){
int parentX = findset(x);
int parentY = findset(y);
if(parentX !=parentY){
unite(parentX,parentY);
return true;
}
return false;
}
}
public boolean containsCycle(char[][] grid) {
int m = grid.length;
int n = grid[0].length;
UnionFind uf = new UnionFind(m*n);
for(int i=0;i<m;++i){
for(int j = 0;j<n;++j){
if(i>0 && grid[i][j]==grid[i-1][j]){
if(!uf.findAndUnite(i*n+j,(i-1)*n+j)){
return true;
}
}
if(j>0 && grid[i][j]==grid[i][j-1]){
if(!uf.findAndUnite(i*n+j,i*n+j-1)){
return true;
}
}
}
}
return false;
}
}
class Solution {
class UnionFind{
int[] f;
public void initset(){
f = new int[250010];
for(int i = 0;i<250010;i++){
f[i]=i;
}
}
public int findset(int x){
return f[x] == x?x:(f[x]=findset(f[x]));
}
public int unionset(int x,int y){
int fx=findset(x);
int fy=findset(y);
if(fx!=fy){
f[fx]=fy;
return 1;
}
return 0;
}
}
int[][] dir=new int[][] {
{-1,0},{0,1},{1,0},{0,-1}
};
int[][][] data=new int [][][]{
{{-1,-1,-1},{-1,-1,-1},{-1,-1,-1},{-1,-1,-1}},
{{-1,-1,-1},{1,3,5},{-1,-1,-1},{1,4,6}},
{{2,3,4},{-1,-1,-1},{2,5,6},{-1,-1,-1}},
{{-1,-1,-1},{-1,-1,-1},{2,5,6},{1,4,6}},
{{-1,-1,-1},{1,3,5},{2,5,6},{-1,-1,-1}},
{{2,3,4},{-1,-1,-1},{-1,-1,-1},{1,4,6}},
{{2,3,4},{1,3,5},{-1,-1,-1},{-1,-1,-1}}
};
public boolean hasValidPath(int[][] grid) {
UnionFind uf=new UnionFind();
int i,j,k;
int m = grid.length;
int n= grid[0].length;
uf.initset();
for(i=0;i<m;i++){
for(j=0;j<n;++j){
for(k=0;k<4;++k){
int ti=i+dir[k][0];
int tj=j+dir[k][1];
if(ti<0||tj<0||ti==m||tj==n){
continue;
}
int a = i*n+j;
int b = ti*n+tj;
int ag = grid[i][j];
int bg = grid[ti][tj];
if(data[ag][k][0]==bg|| data[ag][k][1]==bg || data[ag][k][2]==bg){
uf.unionset(a,b);
}
}
}
}
return uf.findset(0)==uf.findset(m*n-1);
}
}
class Solution {
int[] f;
public void initset(int n){
f = new int[n];
for(int i = 0;i<n;i++){
f[i]=i;
}
}
public int findset(int x){
if(x!=f[x]){
f[x]=findset(f[x]);
}
return f[x];
}
public String smallestStringWithSwaps(String s, List<List<Integer>> pairs) {
int n = s.length();
initset(n);
for(int j=0; j<pairs.size();j++){
List<Integer> pa = pairs.get(j);
int pre = pa.get(0);
int aft = pa.get(1);
int preP = findset(pre);
int aftP = findset(aft);
if(preP == aftP){
continue;
}
f[preP] = aftP;
}
Map<Integer,PriorityQueue<Character>> map = new HashMap<>();
for(int k = 0;k<n;k++){
PriorityQueue<Character> queue = map.getOrDefault(findset(k),new PriorityQueue<>());
queue.offer(s.charAt(k));
map.put(f[k],queue);
}
StringBuilder sb=new StringBuilder();
for(int r=0;r<n;r++){
PriorityQueue<Character> tq = map.get(findset(r));
sb.append(tq.poll());
}
return sb.toString();
}
}