You are given a string s
, and an array of pairs of indices in the string pairs
where pairs[i] = [a, b]
indicates two 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.
For example:
s = "dcab", pairs = [[0,3],[1,2]]
. Output: "bacd"
Explanation:
Swap s[0]
and s[3]
, s = "bcad"
Swap s[1]
and s[2]
, s = "bacd"
s = "dcab", pairs = [[0,3],[1,2],[0,2]]
. Output: "abcd"
Explanation:
Swap s[0]
and s[3]
, s = "bcad"
Swap s[0]
and s[2]
, s = "acbd"
Swap s[1]
and s[2]
, s = "abcd"
s = "cba", pairs = [[0,1],[1,2]]
. Output: "abc"
Explanation:
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 lowercase English letters.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to finding the smallest string with swaps involves trying every single possible combination of swaps. We generate each possible string arrangement and check if it's smaller than our current smallest string. This is like trying every key on a keyring until you find the one that opens the lock.
Here's how the algorithm would work step-by-step:
def smallest_string_with_swaps_brute_force(original_string, allowed_swaps):
smallest_string = original_string
string_length = len(original_string)
# Iterate through all possible combinations of swaps
for i in range(1 << len(allowed_swaps)):
new_string = list(original_string)
indices_to_swap = []
# Determine which swaps to perform based on the binary representation of i
for swap_index in range(len(allowed_swaps)):
if (i >> swap_index) & 1:
indices_to_swap.append(allowed_swaps[swap_index])
# Apply the swaps if any swaps are selected
if indices_to_swap:
# Sort indices to maintain consistency
indices_to_swap.sort()
#Group characters to preserve order
characters_to_swap = [new_string[index_pair[0]] for index_pair in indices_to_swap]
characters_to_swap.sort()
# Apply the sorted characters to the selected indices
for char_index in range(len(indices_to_swap)):
new_string[indices_to_swap[char_index][0]] = characters_to_swap[char_index]
new_string = "".join(new_string)
# Update the smallest string if the new string is smaller
if new_string < smallest_string:
smallest_string = new_string
return smallest_string
The key idea is to group together positions where letters can be swapped. Then, within each group, we want to arrange the letters in the best possible order, which is alphabetically.
Here's how the algorithm would work step-by-step:
def smallest_string_with_swaps(input_string, pairs_of_indices):
string_length = len(input_string)
parent = list(range(string_length))
def find(index):
if parent[index] != index:
parent[index] = find(parent[index])
return parent[index]
def union(index_one, index_two):
root_one = find(index_one)
root_two = find(index_two)
parent[root_one] = root_two
# Use union-find to determine connected components
for index_one, index_two in pairs_of_indices:
union(index_one, index_two)
connected_components = {}
for index in range(string_length):
root = find(index)
if root not in connected_components:
connected_components[root] = []
connected_components[root].append(index)
result_string_list = list(input_string)
# Sort the characters within each connected component
for root, indices in connected_components.items():
characters = [input_string[index] for index in indices]
characters.sort()
indices.sort()
# Assign the sorted characters back to the string
for index, character in zip(indices, characters):
result_string_list[index] = character
return "".join(result_string_list)
Case | How to Handle |
---|---|
Null or empty string s | Return an empty string or throw an exception if input string s is null or empty. |
Null or empty pairs list | Return the original string if the pairs list is null or empty, as no swaps are specified. |
String s has length 1 | Return the original string as no swaps can change the string. |
Pairs list contains invalid indices (out of string bounds) | Ignore the invalid pair or throw an exception to prevent array out-of-bounds errors. |
Pairs list contains duplicate pairs | The union-find data structure handles this as redundant pairs are merged in the same connected component. |
Pairs form cycles in the string indices | The union-find approach correctly identifies connected components even when they contain cycles. |
All characters in the string are the same | The algorithm should still correctly group the indices and sort the corresponding characters within the connected components. |
Very long string and very large pairs list exceeding memory limits | Consider using an iterative depth-first search instead of recursion in the union-find algorithm to avoid stack overflow and optimize memory usage. |