首先并查集就是 :将有关系的元素分为一个集合,其中当发现任意两个不相干的集合中的任意两个元素,就将两集合合并。
并查集分为两个重要步骤:1. 查询路径 2. 合并路径
本题中涉及到部分元素相互连续的特点,最大根节点,符合并查集逻辑。
下面是需要讲解的关键代码思路:
变量说明:*********************************
****************f[i] 是存储原始顺序************
****************data[i] 是存储题目数据**********
****************************************************
int k=find(data[i])-----*1*
就会如图所示如果find(data[i])==i ,其实就是未出现的意思,反过来想find(data[i])!=i 就是已出现的意思。。这段代码就是省略了去cherk(到底这个数有没有出现过),不管怎样 我给你分析一波,第一个情况(没出现)就是如图所示的 1 节点,将1 节点的父节点+1,,,,第二个情况(出现了)(比如我再输入1)前面有过1了找find(1)其实变成了root 2将 2 赋值给 第二次输入的1 ,父节点再加一,如果我再输入2,find(2)就是root 3,两种情况都是将父节点+1
(就是将父节点理解为当时某个连续区间内连续的数值最大节点),此时如果插入连续区间内的数,为了保证后面的数不重复就会被赋值该连续区间的最大值(父节点)这个举动可以保证前面数据不重复,且data[i]当时pos节点能得到合法的最小值。主要运用的就是并查集的查询路径的压缩
代码:
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
static int[] f=new int[2000000];
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
//获取第一行数据
int n=Integer.parseInt(sc.nextLine());
int[] data=new int[n];
//初始化f数组
for (int i = 1; i < f.length; i++) {
f[i]=i;
}
//获取第二行数据,放到数组中
for (int i = 0; i < n; i++) {
data[i]=sc.nextInt();
}
for (int i = 0; i < data.length; i++) {
int k=find(data[i]);
data[i]=k;
f[data[i]]=find(data[i]+1);
}
for (int i = 0; i < data.length; i++) {
System.out.print(data[i]+" ");
}
}
//(并查集)
public static int find(int x) {
if(x==f[x]) {
return x;
}else {
f[x]=find(f[x]);
return f[x];
}
}
}
无论什么时候,生活愉快:)