力扣题1202
题目描述:
实现如下:
class Solution:
def smallestStringWithSwaps(self, s: str, pairs: list[list[int]]) -> str:
# 初步思路 因为s都是由小写字母组成的 要想最后的字符串最小
# 就应该要比较小的字母往前排即可 从a开始 若字符串中存在a 就尽量使得a往前排(通过pairs可以知道最前可以往哪里排)
# 然后排b 就这样循环 结束 (注意:前后置换的时候 要肯定前者大于后者 否则就停止)
# 实质上就是图的遍历查询 从一个地方是否可以置换到另一个地方
# 但是根据题中已知条件 内存不够 无法存储如此大的图结构
# 进阶想法 a往最前面置换的时候 和他可以置换的其他字母 和他是一组的(可以经过相同的路线置换)
# 所以 可以选择按组分类 只要元素之间可以相互交换 那么他们就是一组的
# 这样先把组分号 然后组内排好序
# 最后 按照原始的字符串顺序 从对应的所在组内选出最小值就可以了
# (只要在同一组内 经过若干次置换 肯定可以将最小元素到达该位置
# 可用s = "cba", pairs = [[0,1],[1,2]]试验 可以得到任意一种顺序)
# 这就是所谓的并查集!!!
# 最终实现 根据上述思路 我只需要将pairs按是否可以相互置换合并成组
# 然后取到组内对应元素 排序 在填回字符串
# 执行完所有的分组即可
if len(pairs) == 0:
return s
# 这样的合并方法居然超时了呀 难受
# list_group = [[pairs[0][0], pairs[0][1]]]
# for x in pairs[1::]:
# # 当前分组能否包含现有的数据
# flag1 = 0
# # 可能存在一组数据 使得两个分组合并的情况出现 设置判断
# # 最多使两个分组合并哟
# flag2 = -1
# for y in range(len(list_group)):
# if x[0] in list_group[y]:
# flag1 = 1
# if x[1] not in list_group[y]:
# if flag2 == -1:
# list_group[y].append(x[1])
# flag2 = y
# else:
# list_group[flag2] = list(set(list_group[flag2] + list_group[y]))
# list_group.pop(y)
# break
# elif x[1] in list_group[y]:
# flag1 = 1
# if flag2 == -1:
# list_group[y].append(x[0])
# flag2 = y
# else:
# list_group[flag2] = list(set(list_group[flag2] + list_group[y]))
# list_group.pop(y)
# break
# if flag1 == 0:
# list_group.append(x)
# print(list_group)
n = len(s)
parent = {i: i for i in range(n)}
# 并查集 递归到根节点
def find(x):
if x != parent[x]:
parent[x] = find(parent[x])
return parent[x]
# 查找根节点
for l, r in pairs:
a, b = find(l), find(r)
parent[b] = a
# 获取根节点对应的连通块集合
dic = collections.defaultdict(list)
for i in range(n):
root = find(i)
dic[root].append(i)
s = list(s)
for x in dic.values():
if len(x) > 1:
x.sort()
group = []
for y in x:
group.append(s[y])
group.sort()
i = 0
for y in x:
s[y] = group[i]
i += 1
return ''.join(s)
这里涉及到一个新东西 新知识 并查集
刚开始想的时候 想到了这样的方法 但是并不知道这个叫并查集
看了评论才明白的
这里主要想表述一下 并查集和图的连通子图的区别吧
其实说白了 并查集的问题属于图的问题 但是 却不能用图的方法实现
原因就是 并查集对应的问题太过于庞大 用图进行解题的话 无法进行存储(内存放不下)
存储都是问题 其他的就免谈了 毕竟第一步是要先把图存到内存 才可以有接下来的操作
那么什么时候用图的知识解决呢?
第一 内存可以存储的下整张图
第二 题中给出的两点链接方式就是图的二维矩阵存储方法
如[[1,1,0],[1,1,0],[0,0,1]]
什么时候用并查集呢?
第一 结点个数太多 无法进行存储解决
第二 给出的是点对点的对应关系
如[[0,3],[1,2],[0,2]]
并查集的通用代码:`
n = len(s)
parent = {i: i for i in range(n)}
# 并查集 递归到根节点
def find(x):
if x != parent[x]:
parent[x] = find(parent[x])
return parent[x]
# 查找根节点
for l, r in pairs:
a, b = find(l), find(r)
parent[b] = a
# 获取根节点对应的连通块集合
dic = collections.defaultdict(list)
for i in range(n):
root = find(i)
dic[root].append(i)
那么最后dic.values()中就是存储所有的分组情况了
加油加油你最棒!