Given a string s
, remove duplicate letters so that every letter appears once and only once. You must make sure your result is the smallest in lexicographical order among all possible results.
Example 1:
Input: s = "bcabc" Output: "abc"
Example 2:
Input: s = "cbacdcbc" Output: "acdb"
Constraints:
1 <= s.length <= 104
s
consists of lowercase English letters.Note: This question is the same as 1081: https://leetcode.com/problems/smallest-subsequence-of-distinct-characters/
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 strategy for removing duplicate letters involves exploring every single possible combination of letters from the input. We aim to find the lexicographically smallest string that contains each unique letter exactly once. This approach is essentially trying out all possibilities and seeing which one fits the criteria and is the best.
Here's how the algorithm would work step-by-step:
def remove_duplicate_letters_brute_force(input_string):
unique_characters = sorted(list(set(input_string)))
import itertools
all_permutations = list(itertools.permutations(unique_characters))
best_valid_arrangement = None
for permutation in all_permutations:
arrangement_string = ''.join(permutation)
is_valid = True
# Check if current arrangement is valid
input_index = 0
arrangement_index = 0
while input_index < len(input_string) and arrangement_index < len(arrangement_string):
if input_string[input_index] == arrangement_string[arrangement_index]:
arrangement_index += 1
input_index += 1
# If the permutation doesn't appear in order, it's not valid
if arrangement_index != len(arrangement_string):
is_valid = False
if is_valid:
#Find the lexicographically smallest permutation
if best_valid_arrangement is None or arrangement_string < best_valid_arrangement:
best_valid_arrangement = arrangement_string
return best_valid_arrangement
The goal is to find the smallest string with all unique letters from the input, keeping the original order as much as possible. We achieve this by making 'greedy' decisions, prioritizing letters that appear later in the string if we have a choice. This ensures we don't prematurely remove letters needed later.
Here's how the algorithm would work step-by-step:
def remove_duplicate_letters(input_string):
letter_counts = {}
for letter in input_string:
letter_counts[letter] = letter_counts.get(letter, 0) + 1
result_stack = []
seen_letters = set()
for letter in input_string:
# If letter not already in result, add it while maintaining order.
if letter not in seen_letters:
while result_stack and letter < result_stack[-1] and letter_counts[result_stack[-1]] > 0:
# Remove larger letter if it appears later to obtain optimal ordering.
removed_letter = result_stack.pop()
seen_letters.remove(removed_letter)
result_stack.append(letter)
seen_letters.add(letter)
letter_counts[letter] -= 1
return ''.join(result_stack)
Case | How to Handle |
---|---|
Empty string input | Return an empty string immediately as there are no characters to process. |
String with only one unique character | Return the string as is since there are no duplicates to remove. |
String with all the same characters (e.g., 'aaaa') | Return the single character once, as all are duplicates. |
String with characters in reverse lexicographical order (e.g., 'zyx') | The algorithm should still produce a valid result by choosing the rightmost smallest character. |
String with a large number of duplicate characters clustered together | The algorithm needs to efficiently handle these clusters without excessive backtracking. |
String containing all lowercase letters of the alphabet in reverse order ('zyxwvutsrqponmlkjihgfedcba') | This tests the algorithm's ability to handle the worst-case scenario, which might expose performance issues. |
String containing only duplicate characters except for one at the end | Ensure the unique character is not incorrectly skipped or excluded. |
String of maximum allowed length (consider memory constraints and algorithm complexity) | Verify the chosen data structures (e.g., stacks, frequency maps) can handle maximum input size without errors such as stack overflow or out of memory. |