diff --git a/1308_smallest-string-with-swaps/README.md b/1308_smallest-string-with-swaps/README.md new file mode 100644 index 0000000..6ca5255 --- /dev/null +++ b/1308_smallest-string-with-swaps/README.md @@ -0,0 +1,42 @@ +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 1:** + + 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" + + +**Example 2:** + + Input: s = "dcab", pairs = [[0,3],[1,2],[0,2]] + Output: "abcd" + Explaination: + Swap s[0] and s[3], s = "bcad" + Swap s[0] and s[2], s = "acbd" + Swap s[1] and s[2], s = "abcd" + +**Example 3:** + + Input: s = "cba", pairs = [[0,1],[1,2]] + Output: "abc" + Explaination: + Swap s[0] and s[1], s = "bca" + Swap s[1] and s[2], s = "bac" + Swap s[0] and s[1], s = "abc" + + +**Constraints:** + +* `1 <= s.length <= 10^5` +* `0 <= pairs.length <= 10^5` +* `0 <= pairs[i][0], pairs[i][1] < s.length` +* `s` only contains lower case English letters. + +https://leetcode.com/problems/smallest-string-with-swaps \ No newline at end of file diff --git a/1308_smallest-string-with-swaps/python3/solution.py b/1308_smallest-string-with-swaps/python3/solution.py new file mode 100644 index 0000000..1d36b62 --- /dev/null +++ b/1308_smallest-string-with-swaps/python3/solution.py @@ -0,0 +1,52 @@ +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)