Given a string s
, find the length of the longest substring without duplicate characters.
For example:
s = "abcabcbb"
. The answer is "abc"
, with a length of 3.s = "bbbbb"
. The answer is "b"
, with a length of 1.s = "pwwkew"
. The answer is "wke"
, with a length of 3. Note that the answer must be a substring; "pwke"
is a subsequence and not a substring.How would you approach this problem? What is the time and space complexity of your solution? Are there any edge cases to consider?
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 method finds the longest substring without repeating characters by examining every possible substring. It involves checking each substring to see if it meets the criteria. We continue until the longest valid substring is found.
Here's how the algorithm would work step-by-step:
def longest_substring_without_repeating_characters_brute_force(input_string):
longest_substring_length = 0
for starting_index in range(len(input_string)): # Iterate through possible starting positions
for ending_index in range(starting_index, len(input_string)): # Iterate through possible ending positions
substring = input_string[starting_index:ending_index + 1]
# Check if the current substring has repeating characters
if len(set(substring)) == len(substring):
# Update the length if this substring is the longest so far
longest_substring_length = max(longest_substring_length, len(substring))
return longest_substring_length
The optimal strategy avoids unnecessary work by remembering the last time we saw each letter. This lets us quickly move the start of our substring when we encounter a duplicate, skipping over many invalid substrings all at once.
Here's how the algorithm would work step-by-step:
def length_of_longest_substring(input_string):
start_index = 0
max_length = 0
character_index_map = {}
for end_index, character in enumerate(input_string):
#If char is present and within current window
if character in character_index_map and start_index <= character_index_map[character]:
# Move the start of window
start_index = character_index_map[character] + 1
else:
# Update max length if needed
max_length = max(max_length, end_index - start_index + 1)
character_index_map[character] = end_index
return max_length
Case | How to Handle |
---|---|
Null or Empty String | Return 0, as an empty string has no substring. |
String with a single character | Return 1, as a single character string has a substring of length 1. |
String with all identical characters (e.g., 'aaaa') | The sliding window will increment its right pointer and update the starting index of the window when a duplicate is found, ultimately returning 1. |
String with many repeating characters (e.g., 'abababab') | The algorithm will dynamically adjust the window based on the locations of duplicates, ensuring correct substring length tracking. |
String with no repeating characters (e.g., 'abcdefg') | The sliding window will expand to the entire string and return the length of the string. |
String with ASCII characters or Unicode characters. | The sliding window/hashmap must be able to handle the full range of characters provided in the string. |
Long string to check for performance and potential memory overflow | The sliding window approach provides O(n) time complexity and uses constant space for character storage. |
String contains only whitespace characters | The algorithm should correctly handle whitespace characters the same as any other character, either returning 1 if all are identical, or the length of the substring if unique spaces are present. |