1. 问题描述:
给你一个字符串 s,以及该字符串中的一些「索引对」数组 pairs,其中 pairs[i] = [a, b] 表示字符串中的两个索引(编号从 0 开始)。你可以 任意多次交换 在 pairs 中任意一对索引处的字符。返回在经过若干次交换后,s 可以变成的按字典序最小的字符串。
示例 1:
输入:s = "dcab", pairs = [[0,3],[1,2]]
输出:"bacd"
解释:
交换 s[0] 和 s[3], s = "bcad"
交换 s[1] 和 s[2], s = "bacd"
示例 2:
输出:"abcd"
解释:
交换 s[0] 和 s[3], s = "bcad"
交换 s[0] 和 s[2], s = "acbd"
交换 s[1] 和 s[2], s = "abcd"
示例 3:
输入:s = "cba", pairs = [[0,1],[1,2]]
输出:"abc"
解释:
交换 s[0] 和 s[1], s = "bca"
交换 s[1] 和 s[2], s = "bac"
交换 s[0] 和 s[1], s = "abc"
提示:
1 <= s.length <= 10^5
0 <= pairs.length <= 10^5
0 <= pairs[i][0], pairs[i][1]
s 中只含有小写英文字母
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/smallest-string-with-swaps
2. 思路分析:
① 一开始的时候发现题目真的挺难,没有啥思路,所以放弃自己思考,看一下评论区的题解,发现大部分使用的是并查集来解决的,假如能够互通连接在一起的节点,我们是可以先确定某些一个或者某些字母将其放在对应的位置,这样这些字母后面是不需要移动的了,然后通过交换剩余可以改变位置的字母最终得到字典序最小的字母序列,简单来说就是将连在一起的节点中的字母进行排序,这样得到的肯定是字典序最小的序列,因为我是可以通过若干次的移动确定所有字母的位置并且将其放在对应的位置上的,其实这也就是并查集的问题
② 我们在一开始的时候初始化每一个节点的父节点,在遍历的时候修改当前节点的父节点,另外声明一个字典用来添加连在一起的节点,这样我们就可以对连在一起的节点范围内的字母进行排序组成字典序更小的序列,这个思路还是蛮好理解的
③ 其中会使用到collections.defaultdict(list)函数用来创建一直接可以使用键访问的字典,并且使用zip函数可以将下标与对应字母的列表一一进行对应这样就可以添加到结果集中了,下面的代码是领扣评论区中的代码:
https://leetcode-cn.com/problems/smallest-string-with-swaps/solution/bing-cha-ji-python-by-fa-kuang-de-jie-zi/
,在python学习的过程中可以多看看别人写的代码可以多学习一下各种各种常见的函数,对于自己的熟悉各种函数的方法也是非常有好处的(感觉刷题思考看别人写的代码是一个很快学习常见函数用法的方法)
3. 代码如下:
import collections
class Solution:
def smallestStringWithSwaps(self, s: str, pairs: [int]) -> str:
# 字典: 初始化每一个节点的父节点
p = {i: i for i in range(len(s))}
# 递归: 在查询x节点的时候修改x的父节点
def f(x):
if x != p[x]:
p[x] = f(p[x])
return p[x]
# 在遍历的时候修改节点的父节点
for i, j in pairs:
p[f(j)] = f(i)
# 合并可交换位置
# 使用字典将所有在同一个父节点的节点联系起来
d = collections.defaultdict(list)
# 使用map函数迭代调用f函数, 传入方法中的是字典中的键
for i, j in enumerate(map(f, p)):
d[j].append(i)
# 排序
ans = list(s)
for q in d.values():
# 注意返回的是列表
t = sorted(ans[i] for i in q)
# zip函数返回一个元祖
for i, c in zip(sorted(q), t):
ans[i] = c
return ''.join(ans)