并查集相关知识

并查集常用模板

class UnionSet:def init_tree(self,n):self.fa = [i for i in range(n)] # 必要,记录根节点,也可能是字典形式self.cnt = collections.defalutdict(lambda :1) # 不一定必要,用于计算树的高度def find(self,x): # 寻找根节点,并状态压缩while self.fa[x]!=x:x= self.fa[x]return xdef union(self,u,v): # 合并ru = self.find(u)rv = self.find(v)if ru == rv:return self.fa[ru] = rvreturn

1、LeetCode900、等式方程的可满足性

题目描述

题解思路

  1. 等式具有传递性,将a-z映射成0-25一共26个数字
  2. 遍历所有的等式,将等式左右两边的字母(已经转换成数字了)连通起来
  3. 遍历所有的不等式,如果等式左右两边字母的根节点一样,与不等这个条件矛盾,返回False
  4. 遍历结束,返回True

python代码

class Solution:# 并查集,等式具有传递性def init_tree(self,n):self.fa = [i for i in range(n)]def find(self,x):while self.fa[x]!=x:x= self.fa[x]return xdef union(self,u,v):ru = self.find(u)rv = self.find(v)if ru == rv:return self.fa[ru] = rvreturn def equationsPossible(self, equations: List[str]) -> bool:self.init_tree(26) # 初始化并查集for s in equations: # 遍历等式if s[1] == '=': index1 = ord(s[0])-ord('a')index2 = ord(s[3])-ord('a')self.union(index1,index2)for s in equations: # 遍历不等式if s[1] == '!':index1 = ord(s[0])-ord('a')index2 = ord(s[3])-ord('a')if self.find(index1) == self.find(index2):return Falsereturn True

2、LeetCode1319、连通网络的操作次数

题目描述

题解思路

  1. 总共需要n-1个线缆
  2. 如果两个计算机的根节点一样,可以节省一根线
  3. 判断还需要的线缆数目和省下来的线缆的数目,如果后者大,返回前者,否则返回-1

Python代码

class Solution:def init_tree(self,n):self.fa = [i for i in range(n)]def find(self,x):while self.fa[x]!=x:x= self.fa[x]return xdef union(self,u,v):ru = self.find(u)rv = self.find(v)if ru == rv:return self.fa[ru] = rvreturn def makeConnected(self, n: int, connections: List[List[int]]) -> int:# 总共需要n-1个线缆# 如果两个计算机的跟节点一样,可以省一根线,假设省x根# if (n-1)-(len(connections)-x)>x:return -1 else return 前面的部分self.init_tree(n)x = 0for s in connections:if self.find(s[0])!=self.find(s[1]):self.union(s[0],s[1])else:x+=1res = (n-1)-(len(connections)-x)return res if res<=x else -1

可以看到基本上并查集部分的模板代码是几乎不怎么需要改变的!!!

3、LeetCode684、冗余连接

题目描述

题解思路

  1. 遍历节点,如果一条边的两个顶点的根节点不一样,就进行合并
  2. 如果一样,说明已经形成环了,直接返回(如示例1,节点2和3的根节点都是1,而[2,3]表示的又是2,3之间有边,所以已经成环了)

Python代码

class Solution:# 并查集# 遍历节点,如果一条边的两个顶点的父节点不一样,就合并;# 如果一样,说明形成环了,直接返回def init_tree(self,n):self.fa = [i for i in range(n)]def find(self,x):while self.fa[x]!=x:x= self.fa[x]return xdef union(self,u,v):ru = self.find(u)rv = self.find(v)if ru == rv:return self.fa[ru] = rvreturn def findRedundantConnection(self, edges: List[List[int]]) -> List[int]:n = len(edges)self.init_tree(n)for i in range(n): # 调用find函数要注意find中的索引应该是[0,len(self.fa)-1]if self.find(edges[i][0]-1) != self.find(edges[i][1]-1): # 因为self.fa=[1,2,3],但是索引从0开始self.union(edges[i][0]-1,edges[i][1]-1)else:return edges[i]return -1

4、LeetCode128、最长连续子序列

题目描述

题解思路

  1. 除了要初始化根节点以外,还要初始化每个根节点对应的树的高度
  2. 并查集的连接函数需要修改一下,即要有具体的返回值,如果两棵树的根节点一样,就将两个数的高度加起来,并返回
  3. 遍历数组,迭代更新当前数与(当前数+1)的连接结果

Python代码

class Solution:def init_tree(self,nums):self.fa = {num:num for num in nums}self.cnt = collections.defaultdict(lambda:1)def find(self,x):while self.fa[x]!=x:x = self.fa[x]return xdef union(self,u,v):if v not in self.fa:return 1ru = self.find(u)rv = self.find(v)if ru == rv:return self.cnt[ru]self.fa[ru] = rvself.cnt[rv]+=self.cnt[ru]return self.cnt[rv]def longestConsecutive(self, nums: List[int]) -> int:# 方法1、模拟# nums = list(set(nums))# nums.sort()# index = 0# count = 1 # 记录连续序列长度# res = 0 # 记录结果# while index<len(nums):#     if nums[index]+1 in  nums:#         count+=1#     else:#         count = 1 # 不连续,就重头开始计数#     res = max(res,count)#     index+=1# return res# 方法2,并查集n = len(nums)res = 0self.init_tree(nums)for num in nums:res = max(res,self.union(num,num+1))return res

注意到这里初始化并查集的根节点,使用的是哈希表而不是数组,因为给定的数字数组并不是连续的

5、LeetCode947、移除最多的同行同列的石头

题目描述


提示:

1 <= stones.length <= 1000
0 <= xi, yi <= 10**4
不会有两块石头放在同一个坐标点上

题解思路

  1. 可以给nums中每个坐标定义一个索引,然后如果两个坐标含有相同的横纵坐标,就连通两个坐标
  2. 最后查看有几个独立的并查集集合,也就是最终留下的坐标个数x
  3. 返回len(nums)-x即可

Python代码

class Solution:def init_tree(self,n):self.fa = [i for i in range(n)]def find(self,x):while self.fa[x]!=x:x= self.fa[x]return xdef union(self,u,v):ru = self.find(u)rv = self.find(v)if ru == rv:return self.fa[ru] = rvreturn def removeStones(self, stones: List[List[int]]) -> int:self.init_tree(len(stones))for i in range(len(stones)-1):for j in range(i+1,len(stones)):if stones[i][0]==stones[j][0] or stones[i][1]==stones[j][1]:self.union(i,j)hashmap = {}for i in range(len(stones)):hashmap[i] = self.find(i)return len(stones)-len(set(hashmap.values()))

但是此种方法时间复杂度较高,需要两次遍历,还可以继续优化
实际上,只需要将每个点的横纵坐标连通起来就可以了,但是并查集是一个一维的数据结构,横坐标=2,显然和纵坐标=2是不一样的2,于是为了区分,考虑到横纵坐标的取值范围,将纵坐标+1000即可

class Solution:def init_tree(self,n):self.fa = [i for i in range(n)]def find(self,x):while self.fa[x]!=x:x= self.fa[x]return xdef union(self,u,v):ru = self.find(u)rv = self.find(v)if ru == rv:return self.fa[ru] = rvreturn def removeStones(self, stones: List[List[int]]) -> int:self.init_tree(20000)for x,y in stones:self.union(x,y+10000)  # 并查集是一维的,比如第二行和第二列可能难以区分,故将列+10000转换为一维的return len(stones)-len({self.find(x) for x,y in stones}) # {}表示集合,自动去重

6、LeetCode547、省份数量

题目描述

题解思路

  1. 连接相连的两个城市
  2. 遍历数组,没连接成功一个,独立的省份数量就少一个

Python代码

class Solution:# 并查集def init_tree(self, n) -> None:self.fa = [i for i in range(n)] # 记录每个节点的父节点def find(self, x):while self.fa[x] != x:x = self.fa[x]return xdef union(self, u, v):ru = self.find(u)rv = self.find(v)if ru == rv:return Falseself.fa[ru] = rv # 将ru的根设为rvreturn Truedef findCircleNum(self, M: List[List[int]]) -> int:n = len(M)self.init_tree(n)res = nfor i in range(n):for j in range(i + 1, n):if M[i][j] == 1 and self.union(i, j):res -= 1return res

这里不同的是连接函数中,返回了True和False
带权重的并查集不会,懒得看,看不懂,暂且PASS

LeetCode题库:并查集问题(Python语言实现)相关推荐

  1. Leetcode题库217.存在重复元素(python实现)

    文章目录 思路 代码 思路 1.采用set的性质(无重复元素)解题 2.hash数组 3.字典 4.暴力for循环(小心超时) 代码 class Solution:def containsDuplic ...

  2. Leetcode题库-回旋镖的数量(java语言版)

    题目描述: 给定平面上 n 对不同的点,"回旋镖" 是由点表示的元组 (i, j, k) ,其中 i 和 j 之间的距离和 i 和 k 之间的距离相等(需要考虑元组的顺序). 找到 ...

  3. LeetCode题库第867题 转置矩阵

    LeetCode题库第867题 转置矩阵 LeetCode题库第867题 转置矩阵 我首先想到的方法是新建一个二维的矩阵,然后遍历原来的矩阵,将每一个元素放在新矩阵中该放的位置: // javapub ...

  4. LeetCode题库第888题 公平的糖果棒交换

    LeetCode题库第888题 公平的糖果棒交换 LeetCode第888道题 公平的糖果棒交换 首先,题目中说他们两个人的糖果的总数量是不一样的,并且要将A中的一个糖果和B的一个糖果交换后使得他们两 ...

  5. LeetCode题库整理【Java】—— 3 无重复字符的最长子串

    LeetCode题库整理[Java] ## 3 无重复字符的最长子串 题目:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1: 输入: "abcabcbb" ...

  6. LeetCode题库整理【Java】—— 1两数之和

    LeetCode题库整理[Java] 1.两数之和 题目:给定一个整数数组和一个目标值,找出数组中和为目标值的两个数.你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 给定 nu ...

  7. LeetCode题库第2题 两数相加

    两数相加 LeetCode题库第二题 两数相加 看完题目,就可以将题目抽象为三个指针,前两个指针是l1和l2,后一个指针是我们要求的,这三个指针同时移动,由于可能会产生进位,所以可以用一个变量来存储这 ...

  8. LeetCode题库第1题 两数之和

    两数之和 LeetCode题库第1题 两数之和 看到题,我就想到了暴力法: public int[] force(int[] nums,int target) {for (int i = 0; i & ...

  9. LeetCode题库整理【Java】—— 2 两数相加

    LeetCode题库整理[Java] 2.两数相加 题目:给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果, ...

  10. LeetCode题库整理【Java】—— 7整数反转

    LeetCode题库整理[Java] 7.整数反转 题目:给出一个32位的有符号整数,你需要将这个这个整数中每位上的数字进行反转. 示例1: 输入: 123 输出: 321 示例2: 输入: -123 ...

最新文章

  1. xml信息管理系统_WPF信息管理系统项目实战教程二:使用XAML实现页面布局
  2. Java 数组长度和访问
  3. windows10 系统设置一键备份
  4. ……OleContainer中嵌入WORD后,用什么办法显示滚动条???……
  5. S5PC100基于I2C子系统的lm75驱动流程图
  6. ps查看所有php进程,ps命令就是最基本进程查看命令
  7. python中递归函数写法_python递归函数用法详解
  8. linux之trap命令
  9. 如何用Pygame写游戏(五)
  10. matlab概率及数理统计学习-T检验、卡方检验、直方图分布检验
  11. linux buffer cache 过高_怎么理解内存中的Buffer和Cache?
  12. 【树链剖分/倍增模板】【洛谷】3398:仓鼠找sugar
  13. SCSA之信息安全概述
  14. CSS DIV 折角的代码
  15. 超详细的cookie属性HttpOnly和SameSite引起的漏洞解决方案
  16. 一文读懂微生物扩增子16s测序
  17. BIOS实战之HW monitor
  18. 在CMD中输入adb命令,提示“'adb' 不是内部或外部命令,也不是可运行程序或批处理文件”的解决方法
  19. 深度测评小程序跨端开发框架
  20. github首次使用提交项目

热门文章

  1. [JVM]了断局: “运行时数据区“理论梳理
  2. mul matlab,[转载]Matlab boxplot for Mul
  3. Java web15
  4. ext4数据恢复实战及文件系统结构详解
  5. Spring Cloud Data Flow流处理入门-5
  6. 6 2018-SAE-based classification of school-aged children with ASD using functional magnetic resonanc
  7. 利用python实现计算不同长度蛋白质RMSD
  8. eLife | 利用进化信息预测蛋白质界面间残基-残基相互作用
  9. 白嫖党必备非常好用的苹果cms模板网站
  10. 【装机知识】CPU散热器知识整理