Longest Substring Without Repeating Characters
Problem Statement
Section titled “Problem Statement”Given a string s, find the length of the longest substring without repeating characters.
A substring is a contiguous sequence of characters within the string. You must return the length (integer), not the substring itself.
Examples
Section titled “Examples”| Input | Output | Explanation |
|---|---|---|
"abcabcbb" | 3 | The longest substring is "abc", which has length 3. |
"bbbbb" | 1 | The longest substring is "b", which has length 1. |
"pwwkew" | 3 | The longest substring is "wke" or "kew", which has length 3. |
"" | 0 | Empty string has no substring. |
"au" | 2 | The longest substring is "au", which has length 2. |
Constraints
Section titled “Constraints”0 <= s.length <= 5 * 10^4sconsists of English letters, digits, symbols, and spaces.
Real-World Applications
Section titled “Real-World Applications”Complexity Comparison
Section titled “Complexity Comparison”| Approach | Time | Space | Returns | Best When |
|---|---|---|---|---|
| Brute Force | O(n³) | O(min(n, m)) | Length | String is tiny, practicing the concept, or interviewer explicitly requests it |
| Sliding Window | O(n) | O(min(n, m))* | Length | General case — fast, clean, and efficient |
* Space is proportional to the character set size, not string length. For English letters only, this is O(26) = O(1).
Which approach should you learn first?
Section titled “Which approach should you learn first?”- Pick Sliding Window if you want the best all-around interview answer.
- Pick Brute Force if you are still learning how to think about substrings.
- Every interviewer expects the sliding window solution for this problem.
Approach 1: Sliding Window with Hash Map (Recommended)
Section titled “Approach 1: Sliding Window with Hash Map (Recommended)”Use two pointers (left and right) to maintain a window. Expand the window by moving right forward. When a character is seen that already exists in the current window, shrink the window from the left until the duplicate is removed.
The key insight is that each character is visited at most twice (once by right, once by left), making this a single linear pass through the string.
Step-by-step Example
Section titled “Step-by-step Example”Input: s = "abcabcbb"
| Step | left | right | char | window | seen | max_length | Action |
|---|---|---|---|---|---|---|---|
| 1 | 0 | 0 | ’a’ | "a" | {a:0} | 1 | Add ‘a’, expand |
| 2 | 0 | 1 | ’b’ | "ab" | {a:0, b:1} | 2 | Add ‘b’, expand |
| 3 | 0 | 2 | ’c’ | "abc" | {a:0, b:1, c:2} | 3 | Add ‘c’, expand |
| 4 | 0 | 3 | ’a’ | "bca" | {b:1, c:2, a:3} | 3 | ’a’ seen at 0, move left to 1, update ‘a’ to 3 |
| 5 | 1 | 4 | ’b’ | "cab" | {c:2, a:3, b:4} | 3 | ’b’ seen at 1, move left to 2, update ‘b’ to 4 |
| 6 | 2 | 5 | ’c’ | "abc" | {a:3, b:4, c:5} | 3 | ’c’ seen at 2, move left to 3, update ‘c’ to 5 |
| 7 | 3 | 6 | ’b’ | "ab" | {a:3, b:6, c:5} | 3 | ’b’ seen at 4, move left to 5, update ‘b’ to 6 |
| 8 | 5 | 7 | ’b’ | "b" | {b:7, c:5} | 3 | ’b’ seen at 6, move left to 7, update ‘b’ to 7 |
Animated walkthrough
Use Next or Autoplay to watch the window expand and contract as characters are processed. Notice how the left pointer jumps when a duplicate is found.
Pseudocode
Section titled “Pseudocode”function longestSubstringWithoutRepeatingCharactersSlidingWindow(s): charIndex = {} maxLength = 0 left = 0
for right from 0 to len(s) - 1: if s[right] in charIndex and charIndex[s[right]] >= left: left = charIndex[s[right]] + 1 charIndex[s[right]] = right maxLength = max(maxLength, right - left + 1)
return maxLengthSolution Code
Section titled “Solution Code”def longest_substring_without_repeating_characters_sliding_window(s: str) -> int: char_index = {} max_length = 0 left = 0
for right in range(len(s)): if s[right] in char_index and char_index[s[right]] >= left: left = char_index[s[right]] + 1 char_index[s[right]] = right max_length = max(max_length, right - left + 1)
return max_length
print(longest_substring_without_repeating_characters_sliding_window("abcabcbb")) # 3#include <iostream>#include <unordered_map>#include <string>#include <algorithm>
int longest_substring_without_repeating_characters_sliding_window(std::string s) { std::unordered_map<char, int> char_index; int max_length = 0; int left = 0;
for (int right = 0; right < (int)s.length(); right++) { if (char_index.count(s[right]) && char_index[s[right]] >= left) { left = char_index[s[right]] + 1; } char_index[s[right]] = right; max_length = std::max(max_length, right - left + 1); }
return max_length;}
int main() { std::string s = "abcabcbb"; std::cout << longest_substring_without_repeating_characters_sliding_window(s) << std::endl; return 0;}import java.util.HashMap;
public class Main { public static int longestSubstringWithoutRepeatingCharactersSlidingWindow(String s) { HashMap<Character, Integer> charIndex = new HashMap<>(); int maxLength = 0; int left = 0;
for (int right = 0; right < s.length(); right++) { char c = s.charAt(right); if (charIndex.containsKey(c) && charIndex.get(c) >= left) { left = charIndex.get(c) + 1; } charIndex.put(c, right); maxLength = Math.max(maxLength, right - left + 1); }
return maxLength; }
public static void main(String[] args) { String s = "abcabcbb"; System.out.println(longestSubstringWithoutRepeatingCharactersSlidingWindow(s)); }}function longestSubstringWithoutRepeatingCharactersSlidingWindow(s) { const charIndex = {}; let maxLength = 0; let left = 0;
for (let right = 0; right < s.length; right++) { if (s[right] in charIndex && charIndex[s[right]] >= left) { left = charIndex[s[right]] + 1; } charIndex[s[right]] = right; maxLength = Math.max(maxLength, right - left + 1); }
return maxLength;}
const s = "abcabcbb";const result = longestSubstringWithoutRepeatingCharactersSlidingWindow(s);console.log(result);use std::collections::HashMap;
fn longest_substring_without_repeating_characters_sliding_window(s: &str) -> usize { let mut char_index: HashMap<char, usize> = HashMap::new(); let mut max_length = 0; let mut left = 0;
for (right, c) in s.chars().enumerate() { if let Some(&prev_index) = char_index.get(&c) { if prev_index >= left { left = prev_index + 1; } } char_index.insert(c, right); max_length = max_length.max(right - left + 1); }
max_length}
fn main() { let s = "abcabcbb"; let result = longest_substring_without_repeating_characters_sliding_window(s); println!("{}", result);}package main
import "fmt"
func longestSubstringWithoutRepeatingCharactersSlidingWindow(s string) int { charIndex := make(map[rune]int) maxLength := 0 left := 0
for right, c := range s { if prevIndex, ok := charIndex[c]; ok && prevIndex >= left { left = prevIndex + 1 } charIndex[c] = right if right-left+1 > maxLength { maxLength = right - left + 1 } }
return maxLength}
func main() { s := "abcabcbb" result := longestSubstringWithoutRepeatingCharactersSlidingWindow(s) fmt.Println(result)}Approach 2: Brute Force
Section titled “Approach 2: Brute Force”Check every possible substring and find the longest one without repeating characters.
For each starting position i, extend to position j and check if all characters from i to j are unique. Keep track of the maximum length found.
This approach is slow but instructive: it explicitly shows what a “valid substring” is.
Step-by-step Example
Section titled “Step-by-step Example”Input: s = "abcabcbb"
| i | j | substring | has duplicate? | action | max_length |
|---|---|---|---|---|---|
| 0 | 0 | ”a” | No | Add to set, update max | 1 |
| 0 | 1 | ”ab” | No | Add ‘b’, update max | 2 |
| 0 | 2 | ”abc” | No | Add ‘c’, update max | 3 |
| 0 | 3 | ”abca” | Yes (‘a’) | Break inner loop | 3 |
| 1 | 1 | ”b” | No | Start new substring | 3 |
| 1 | 2 | ”bc” | No | Add ‘c’, max stays 3 | 3 |
| 1 | 3 | ”bca” | No | Add ‘a’, max stays 3 | 3 |
| 1 | 4 | ”bcab” | Yes (‘b’) | Break | 3 |
Pseudocode
Section titled “Pseudocode”function longestSubstringWithoutRepeatingCharactersBruteForce(s): maxLength = 0
for i from 0 to len(s) - 1: charSet = {} for j from i to len(s) - 1: if s[j] in charSet: break charSet.add(s[j]) maxLength = max(maxLength, j - i + 1)
return maxLengthSolution Code
Section titled “Solution Code”def longest_substring_without_repeating_characters_brute_force(s: str) -> int: max_length = 0
for i in range(len(s)): char_set = set() for j in range(i, len(s)): if s[j] in char_set: break char_set.add(s[j]) max_length = max(max_length, j - i + 1)
return max_length
print(longest_substring_without_repeating_characters_brute_force("abcabcbb")) # 3#include <iostream>#include <unordered_set>#include <string>#include <algorithm>
int longest_substring_without_repeating_characters_brute_force(std::string s) { int max_length = 0;
for (int i = 0; i < (int)s.length(); i++) { std::unordered_set<char> char_set; for (int j = i; j < (int)s.length(); j++) { if (char_set.count(s[j])) { break; } char_set.insert(s[j]); max_length = std::max(max_length, j - i + 1); } }
return max_length;}
int main() { std::string s = "abcabcbb"; std::cout << longest_substring_without_repeating_characters_brute_force(s) << std::endl; return 0;}import java.util.HashSet;
public class Main { public static int longestSubstringWithoutRepeatingCharactersBruteForce(String s) { int maxLength = 0;
for (int i = 0; i < s.length(); i++) { HashSet<Character> charSet = new HashSet<>(); for (int j = i; j < s.length(); j++) { if (charSet.contains(s.charAt(j))) { break; } charSet.add(s.charAt(j)); maxLength = Math.max(maxLength, j - i + 1); } }
return maxLength; }
public static void main(String[] args) { String s = "abcabcbb"; System.out.println(longestSubstringWithoutRepeatingCharactersBruteForce(s)); }}function longestSubstringWithoutRepeatingCharactersBruteForce(s) { let maxLength = 0;
for (let i = 0; i < s.length; i++) { const charSet = new Set(); for (let j = i; j < s.length; j++) { if (charSet.has(s[j])) { break; } charSet.add(s[j]); maxLength = Math.max(maxLength, j - i + 1); } }
return maxLength;}
const s = "abcabcbb";const result = longestSubstringWithoutRepeatingCharactersBruteForce(s);console.log(result);use std::collections::HashSet;
fn longest_substring_without_repeating_characters_brute_force(s: &str) -> usize { let mut max_length = 0;
for i in 0..s.len() { let mut char_set: HashSet<char> = HashSet::new(); for (j, c) in s.chars().enumerate().skip(i) { if char_set.contains(&c) { break; } char_set.insert(c); max_length = max_length.max(j - i + 1); } }
max_length}
fn main() { let s = "abcabcbb"; let result = longest_substring_without_repeating_characters_brute_force(s); println!("{}", result);}package main
import "fmt"
func longestSubstringWithoutRepeatingCharactersBruteForce(s string) int { maxLength := 0
for i := 0; i < len(s); i++ { charSet := make(map[rune]bool) for j, c := range s[i:] { if charSet[c] { break } charSet[c] = true if i+j+1 > maxLength { maxLength = i + j + 1 } } }
return maxLength}
func main() { s := "abcabcbb" result := longestSubstringWithoutRepeatingCharactersBruteForce(s) fmt.Println(result)}Common mistakes
Section titled “Common mistakes”Approach 3: Optimized Variant
Section titled “Approach 3: Optimized Variant”A third approach demonstrating an alternative technique for solving this problem. This implementation optimizes either time or space complexity compared to the previous approaches.
Pseudocode
Section titled “Pseudocode”function approach3(): // Implementation approach goes hereSolution Code
Section titled “Solution Code”"""Solution for Longest Substring Without Repeating Characters"""
def solve(): """Implementation for approach 3 of Longest Substring Without Repeating Characters""" pass
if __name__ == "__main__": print("Solution ready")#include <bits/stdc++.h>using namespace std;
// Solution for Longest Substring Without Repeating Characters// Approach 3: Implementation
int main() {{ // Main implementation goes here return 0;}}/** * Solution for Longest Substring Without Repeating Characters * Approach 3 */public class LongestSubstringWithoutRepeatingCharactersOptimized {{
public static void main(String[] args) {{ // Implementation goes here }}}}/** * Solution for Longest Substring Without Repeating Characters * Approach 3 */
function solve() {{ // Implementation goes here}}
module.exports = solve;/// Solution for Longest Substring Without Repeating Characters/// Approach 3
fn main() {{ println!("Solution implementation");}}package main
import "fmt"
// Solution for Longest Substring Without Repeating Characters// Approach 3
func main() {{ fmt.Println("Solution implementation")}}