实现并查集

本文介绍了并查集数据结构的实现,包括构造、添加、查找、合并和判断操作。并以此为基础解决LeetCode128题——最长连续序列问题。通过遍历元素,将相邻数合并,最后找到每个数的最远连续右边界,从而得出最长连续子序列的长度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 定义一个并查集的类,并实现基本操作:
class UnionFind{
	// 用Map存储并查集,表达的含义是key的父节点是value
	private Map<Integer,Integer> father;
	// 0.构造函数初始化
	public UnionFind(int n){
		father = new HashMap<Integer,Integer>();
		for(int i = 0;i < n;i++){
			father.put(i,null);
		}	
	}
	// 1.添加:初始加入时,每个元素都是一个独立的集合,因此
	public void add(int x){  // 根节点的父节点为null
		if(!father.containesKey(x)){
			father.put(x,null)
		}
	}
	// 2. 查找:反复查找父节点
	public int findFather(){
		int root = x;
		while(father.get(root)){
			root = father.get(root)
		}
		while(x != root){ // 路径压缩,把x到root上所有节点都挂到root下面
			int original_father = father.get(x); // 保存原来的父节点
			father.put(x,root) // 当前节点挂到根节点下面
			x = original_father; // x 赋值为原来的父节点继续执行刚刚的操作
		}
		return root;
	}
	// 3.合并:把两个集合合并成一个,只需要把其中一个集合的根节点挂到另一个集合的根节点下方
	public void union(int x,int y){ // x的集合与y的集合合并
		int rootX  = find(x)
		int rootY = find(y)
		if(rootX != rootY){ // 节点联通只需要一个共同祖先,无所谓谁是根节点
			father.put(rootX,rootY)
		}
	}
	// 4. 判断:判断两个元素是否同属于一个集合
	public boolean isConnected(int x,int y){
		return find(x) == find(y)
	}
}
  1. 练习: LeetCode 128. 最长连续序列
    使用并查集实现:
// 大致思路:
/** 1.遍历所有元素num,如果num + 1存在,将num加入到num + 1所在的连通分量中;
	2.重新遍历一遍所有元素num,通过find函数找到num所在分量的根节点,即最远右边界,从而求得连续区间的长度。
*/
class UnionFind{
	// 记录每个节点的父节点
	private Map<Integer,Integer> parent;
	public UnionFind(int[] nums){
		parent = new HashMap<>();
		// 初始化父节点为自身
		for(int num : nums){
			parent.put(num,num)
		}
	}
	// 寻找x的父节点,实际上也就是x的最远连续右边界
	public Integer find(int x){
		// nums不包含x
		if(!parent.containsKey(x)){
			return null;
		}
		// 遍历找到x的父节点
		while(x != parent.get(x)){
			// 路径压缩
			parent.put(x,parent.get(parent.get(x)));
			x = parent.get(x)
		}
		return x;
	}
	// 合并两个连通分量(用来将num并入到num+1的连续区间中)
	public void union(int x,int y){
		int rootX = find(x)
		int rootY = find(y)
		if(rootX == rootY){
			return;
		}
		parent.put(rootX,rootY)
	}
}
class Solution{
	public int longestConsecutive(int[] nums){
		UnionFind uf = new UnionFind(nums);
		int ans = 0;
		for(int num : nums){
			// 当num+1存在,将num合并到num+1所在集合中
			if(uf.find(num + 1) != null){
				uf.union(num,num + 1)
			}
		}
		for(int num : nums){
			// 找到num的最远连续右边界
			int right = uf.find(num)
			ans = Math.max(ans,right - num + 1)
		}
		return ans;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

酱子姐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值