Leetcode-1202. 交换字符串中的元素 Smallest String With Swaps (并查集/DFS) -超详细python

题目

给你一个字符串 s,以及该字符串中的一些「索引对」数组 pairs,其中 pairs[i] = [a, b] 表示字符串中的两个索引(编号从 0 开始)。
你可以 任意多次交换 在 pairs 中任意一对索引处的字符。
返回在经过若干次交换后,s 可以变成的按字典序最小的字符串。
链接:https://leetcode.com/problems/smallest-string-with-swaps/

You are given a string s, and an array of pairs of indices in the string pairs where pairs[i] = [a, b] indicates 2 indices(0-indexed) of the string.

You can swap the characters at any pair of indices in the given pairs any number of times.

Return the lexicographically smallest string that s can be changed to after using the swaps.

Example:

Input: s = “dcab”, pairs = [[0,3],[1,2]]
Output: “bacd”
Explaination:
Swap s[0] and s[3], s = “bcad”
Swap s[1] and s[2], s = “bacd”

思路及代码

并查集

  • 将所有可以互换的元素放在同一个集合中,每个集合分别排序,再插入回原来的序列中
  • 并查集是遍历所有边(pair),使所有属于同一个集合的点拥有同一个root
class Solution:
    def smallestStringWithSwaps(self, s: str, pairs: List[List[int]]) -> str:
    	# 寻根
        def root(node):
            if p[node] != node:
                p[node] = root(p[node])
            return p[node]
        
        # p记录根
        p = list(range(len(s)))
        for x, y in pairs:
            px, py = root(x), root(y)
            if px != py:
                p[px] = py
        
        # pdict将所有根作为key,属于这个根的所有元素作为value
        pdict = collections.defaultdict(list)
        for i in range(len(p)):
            pdict[root(p[i])].append(s[i])
        # 将各集合中元素进行排序
        for key in pdict:
            pdict[key].sort(reverse=True)
        
        # root(i)可以找到当前位置在p中对应的根节点
        # pdict[root(i)]是该根节点对应的所有value
        # pop()可以输出当前集合排序最靠前的元素(因为之前sort(reverse=True)了)
        ans = []
        for i in range(len(s)):
            ans.append(pdict[root(i)].pop())
        return "".join(ans)

DFS

class Solution:
    def smallestStringWithSwaps(self, s: str, pairs: List[List[int]]) -> str:
        g = [[] for i in range(len(s))]
        seen = [0] * len(s)
        idx = []
        tmp = []
        ans = [0] * len(s)
        
        # g存储邻接表
        for i,j in pairs:
            g[i].append(j)
            g[j].append(i)
        
        # 用dfs找到所有可以相互转换的元素的集合
        def dfs(node):
            if seen[node]:
                return
            seen[node] = 1
            idx.append(node)
            tmp.append(s[node])
            for nxt in g[node]:
                dfs(nxt)
            
        for i in range(len(s)):
            if seen[i]:
                continue
            dfs(i)
            idx.sort()
            tmp.sort()
            # idx记录集合中原有的index
            # tmp记录集合中原有的元素
            # 两者都sort然后分别插入应有的位置即可
            for j in range(len(idx)):
                ans[idx[j]] = tmp[j]
            idx = []
            tmp = []
            
        return "".join(ans)

复杂度

Union-Find: T = O ( n l o g n + V + E ) T = O(nlogn + V + E) T=O(nlogn+V+E)
DFS: T = O ( n l o g n + k ∗ ( V + E ) ) T = O(nlogn + k*(V+E)) T=O(nlogn+k(V+E))
S = O ( n ) S = O(n) S=O(n)

你可能感兴趣的:(Leetcode,leetcode,python,算法)