leetcode/1308_smallest-string-with-swaps/python3/solution.py

53 lines
2.0 KiB
Python
Raw Permalink Normal View History

2022-04-27 19:46:10 +00:00
from collections import defaultdict
class Solution:
def smallestStringWithSwaps(self, s: str, pairs: List[List[int]]) -> str:
'''
Key idea: if (a, b) indexes can be swapped and (b, c) indexes can
be swapped, then (a, c) can be swapped so infinite swap across (a, b, c).
Can be expanded to cover any other letters that are swappable.
'''
# Make the adjacency list
swapmap = defaultdict(list)
for i, j in pairs:
swapmap[i].append(j)
swapmap[j].append(i)
def dfs(s, vertex, chars, vertices):
chars.append(s[vertex])
vertices.append(vertex)
visited.add(vertex)
for neighbor in swapmap[vertex]:
if neighbor not in visited:
dfs(s, neighbor, chars, vertices)
output = [''] * len(s)
visited = set()
for vertex, _ in enumerate(s):
if vertex not in visited:
connected_chars = []
connected_vertices = []
dfs(s, vertex, connected_chars, connected_vertices)
# This might seem confusing but remember that if we find one character
# with the `vertex` connected (i.e swappable) with other characters, then
# they can all be swapped with each other infinite times. Our goal is to
# get the lexicographically smallest string (i.e most sorted) from doing
# these allowed swaps. Hence, we can go ahead and safely sort the chars
# obtained from DFS of vertex.
connected_chars.sort()
connected_vertices.sort()
for i, connected_vertex in enumerate(connected_vertices):
output[connected_vertex] = connected_chars[i]
return ''.join(output)