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^50 <= pairs.length <= 10^50 <= pairs[i][0], pairs[i][1] < s.lengths only contains lower case English letters.The key idea in #1202 Smallest String With Swaps is to recognize that the swap pairs form connected components in a graph. If two indices are connected directly or indirectly, their characters can be rearranged freely among those positions. This observation transforms the problem into grouping indices and then constructing the lexicographically smallest arrangement within each group.
You can model the problem using Union-Find (Disjoint Set Union) or graph traversal techniques like DFS/BFS. First, connect all indices given in pairs to identify components. For each component, collect the characters belonging to those indices, sort them, and then place the smallest characters back into the sorted index positions to achieve the minimal lexicographic result.
Union-Find is typically preferred because it efficiently merges and finds connected components. After grouping indices, sorting characters within each component ensures the final string is as small as possible. The main costs come from union operations and sorting within components.
| Approach | Time Complexity | Space Complexity |
|---|---|---|
| Union-Find (Disjoint Set Union) | O(n log n + p α(n)) | O(n) |
| DFS/BFS Connected Components | O(n log n + p) | O(n + p) |
NeetCode
Use these hints if you're stuck. Try solving on your own first.
Think of it as a graph problem.
Consider the pairs as connected nodes in the graph, what can you do with a connected component of indices ?
We can sort each connected component alone to get the lexicographically minimum string.
In this approach, we use the Union-Find (also known as Disjoint Set Union, DSU) data structure. This structure helps efficiently group indices that can be swapped. Once we group the indices, we can individually sort characters in each connected component to ensure the smallest lexicographical order.
Steps:
Time Complexity: O(M * α(N) + NlogN), where M is the number of pairs, α is the inverse Ackermann function (very small constant), and N is the length of the string.
Space Complexity: O(N) for the union-find structure and the character groups.
1class UnionFind:
2 def __init__(self, size):
3 self.parent = list(range(size))
4
5 def find(self, x):
6 if self.parent[x] != x:
7 self.parent[x] = self.find(self.parent[x])
8 return self.parent[x]
9
10 def union(self, x, y):
11 rootX = self.find(x)
12 rootY = self.find(y)
13 if rootX != rootY:
14 self.parent[rootY] = rootX
15
16def smallestStringWithSwaps(s, pairs):
17 if not s:
18 return ""
19 n = len(s)
20 uf = UnionFind(n)
21 for x, y in pairs:
22 uf.union(x, y)
23
24 import collections
25 groups = collections.defaultdict(list)
26 for i in range(n):
27 root = uf.find(i)
28 groups[root].append(i)
29
30 res = list(s)
31 for indices in groups.values():
32 sorted_chars = sorted(res[i] for i in indices)
33 for i, char in zip(sorted(indices), sorted_chars):
34 res[i] = char
35 return ''.join(res)The provided Python code defines a UnionFind class to help manage connected components through union and find operations. The 'smallestStringWithSwaps' function makes use of this class to find connected components from the given pairs. For each component, it sorts the characters and places them back in the string res according to their indices.
This approach utilizes Depth-First Search (DFS) to find connected components in a graph that represents swap pairs. Each unique character component is individually sorted to form the smallest possible string.
Steps:
Time Complexity: O(N + M + C log C), where N is the number of nodes, M is the number of edges in the graph (pairs), and C is the size of the largest component.
Space Complexity: O(N + M), as we store the adjacency graph and visit flags.
1using System;
2using System.Collections.Generic;
3using System.Linq;
4
public class Solution {
public string SmallestStringWithSwaps(string s, IList<IList<int>> pairs) {
int n = s.Length;
List<int>[] graph = new List<int>[n];
for (int i = 0; i < n; i++) {
graph[i] = new List<int>();
}
foreach (var pair in pairs) {
graph[pair[0]].Add(pair[1]);
graph[pair[1]].Add(pair[0]);
}
bool[] visited = new bool[n];
char[] result = s.ToCharArray();
for (int i = 0; i < n; i++) {
if (!visited[i]) {
var indices = new List<int>();
var chars = new List<char>();
DFS(i, graph, visited, indices, chars, result);
indices.Sort();
chars.Sort();
for (int j = 0; j < indices.Count; j++) {
result[indices[j]] = chars[j];
}
}
}
return new string(result);
}
private void DFS(int node, List<int>[] graph, bool[] visited, List<int> indices, List<char> chars, char[] result) {
visited[node] = true;
indices.Add(node);
chars.Add(result[node]);
foreach (int neighbor in graph[node]) {
if (!visited[neighbor]) {
DFS(neighbor, graph, visited, indices, chars, result);
}
}
}
}Watch expert explanations and walkthroughs
Practice problems asked by these companies to ace your technical interviews.
Explore More ProblemsJot down your thoughts, approach, and key learnings
All indices within a connected component can swap with each other indirectly, meaning their characters can be rearranged freely. Sorting the characters and placing the smallest ones at the smallest indices ensures the overall string is lexicographically minimal.
Yes, variations of this problem appear in interviews at companies like Google, Amazon, and Meta. It tests knowledge of graph connectivity, Union-Find, and how to combine grouping with sorting to achieve optimal results.
Union-Find (Disjoint Set Union) is the most commonly used data structure for this problem because it efficiently groups indices into connected components. After grouping, sorting the characters within each component gives the smallest possible arrangement.
The optimal approach is to treat the swap pairs as edges in a graph and find connected components using Union-Find or DFS. Once indices in each component are identified, their characters can be sorted and reassigned to produce the lexicographically smallest string.
In this C# implementation, we set up a graph, run a DFS to find connected components, collect indices and characters, and sort them to ensure the characters are placed in the smallest lexicographical order inside the result array. The modified result is then returned.