集合合并
题目描述
给定若干个32位int数字集合,每个集合中的数字无重复,譬如:
{1,2,3} {2,5,6} {8}
将其中交集不为空的集合合并,保证合并完成后所有集合之间无交集,输出合并后的集合个数以及最大集合中元素的个数。
输入描述:
输入格式:
- 第一行为一个数字N,表示集合数。
- 接下来N行,每行一个非空集合,包含若干个数字,数字之间用空格分开。
假设第i个集合的大小为Si,数据满足N<=100000,ΣSi<=500000
输出描述:
输出格式:
- 第一行为合并后的集合个数。
- 第二个为最大集合中元素的个数
解题思路
1.当两集合不存在共同元素
略
2.当两集合存在一个共同元素时,将L1的指针指向L2,并且将ary_L[1]融合到ary_L[2],元素所在的集合也更新为在L3;
3.当两集合存在两个共同元素时,发现L1的指针P已经指向L2, 表示ary_L[2]已经融合了集合L1,并将元素所在的集合设定在L2, 跳过该元素继续下一个循环.
4.当集合L3和L1有共同元素, L1和L2也有共同元素时,将L1、L2的P指针更新指向L3,并将ary_L[2]融合到ary_L[3],并将元素所在集合更新到L3;
5.当集合L3和L1、L2有共同元素, L1和L2也有共同元素时,
- 若先查询到L3和L1有共同元素,L1将L1、L2的P指针更新指向L3,并将ary_L[2]融合到ary_L[3];紧接着查询到L3和L2有共同元素,发现L2的P指针已经指向L3,表示已经融合,跳过;
- 若先查询到L3和L2有共同元素,L1将L1、L2的P指针更新指向L3,并将ary_L[2]融合到ary_L[3];紧接着查询到L3和L1有共同元素,发现L1的P指针已经指向L3,表示已经融合,跳过;
图略
代码
import java.io.*;
public class Main {
public static void main(String[] args)throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int cur_n = n;//当前集合数
int max = 0;//最大集合中的元素个数
int total = 20000000;//要超过32位所能表示的最大数
int[] ele2ary = new int[total];//元素当前所在集合
int[] ary_L = new int[n+1];//当前集合n的长度
int[] ary2p = new int[n+1];//集合n所指向的集合
for(int i=1;i<=n;i++){
String[] elist = br.readLine().split(" ");
for(int j=0;j<elist.length;j++){
int ele = Integer.parseInt(elist[j]);
if(ele2ary[ele]==0){
ele2ary[ele]=i;
ary_L[i]++;
// max = Math.max(max, ary_L[i]);
}else{
int bf = ele2ary[ele]; //当前元素上次存在的集合
ele2ary[ele] = i; //更新当前元素所在集合
while(ary2p[bf]!=0){ //找出元素所在的集合或者合并后的集合,并且将合并集合的各个集合指向当前集合
if(bf==ary2p[bf]) break;//判断是否指向自己
int temp = bf;
bf = ary2p[bf];
ary2p[temp] = i;
}
if(bf!=i){
ary_L[i]+=ary_L[bf];
//max = Math.max(max, ary_L[i]);
cur_n--;
ary2p[bf] = i;//更新最后一个集合,使其,=指向当前集合
}
}
max = Math.max(max, ary_L[i]);
}
}
System.out.println(cur_n);
System.out.println(max);
}
}