medium array/string questions
This commit is contained in:
114
backend/data/questions/longest-substring-without-repeating.yaml
Normal file
114
backend/data/questions/longest-substring-without-repeating.yaml
Normal file
@@ -0,0 +1,114 @@
|
||||
title: Longest Substring Without Repeating Characters
|
||||
slug: longest-substring-without-repeating
|
||||
difficulty: medium
|
||||
leetcode_id: 3
|
||||
leetcode_url: https://leetcode.com/problems/longest-substring-without-repeating-characters/
|
||||
categories:
|
||||
- strings
|
||||
- hash-tables
|
||||
patterns:
|
||||
- sliding-window
|
||||
|
||||
description: |
|
||||
Given a string `s`, find the length of the longest substring without repeating characters.
|
||||
|
||||
constraints: |
|
||||
- 0 <= s.length <= 5 * 10^4
|
||||
- s consists of English letters, digits, symbols and spaces
|
||||
|
||||
examples:
|
||||
- input: 's = "abcabcbb"'
|
||||
output: "3"
|
||||
explanation: "The answer is 'abc', with length 3."
|
||||
- input: 's = "bbbbb"'
|
||||
output: "1"
|
||||
explanation: "The answer is 'b', with length 1."
|
||||
- input: 's = "pwwkew"'
|
||||
output: "3"
|
||||
explanation: "The answer is 'wke', with length 3."
|
||||
|
||||
explanation:
|
||||
approach: |
|
||||
1. Use a sliding window with left and right pointers
|
||||
2. Maintain a set of characters in the current window
|
||||
3. Expand right pointer, adding characters to the set
|
||||
4. When a duplicate is found, shrink from left until duplicate is removed
|
||||
5. Track maximum window size throughout
|
||||
|
||||
intuition: |
|
||||
We're looking for the longest contiguous substring where all characters are unique.
|
||||
A sliding window naturally represents a substring.
|
||||
|
||||
When we encounter a duplicate, the current window is invalid. Instead of restarting
|
||||
from scratch, we shrink the window from the left until the duplicate is removed.
|
||||
This way, we never revisit characters unnecessarily.
|
||||
|
||||
common_pitfalls:
|
||||
- title: Resetting the window incorrectly
|
||||
description: |
|
||||
When finding a duplicate, don't start over from the next character.
|
||||
Instead, shrink from the left until the duplicate is removed.
|
||||
wrong_approach: "left = right when duplicate found"
|
||||
correct_approach: "Increment left until duplicate is out of window"
|
||||
|
||||
- title: Not handling empty string
|
||||
description: |
|
||||
An empty string should return 0. Make sure the algorithm handles this.
|
||||
|
||||
- title: Off-by-one in length calculation
|
||||
description: |
|
||||
Window length is right - left + 1, or just track max before removing.
|
||||
|
||||
key_takeaways:
|
||||
- Sliding window is ideal for substring problems with constraints
|
||||
- Use a set or map to track elements in current window
|
||||
- Shrinking from one end maintains the contiguous property
|
||||
- This pattern appears in many "longest/shortest with constraint" problems
|
||||
|
||||
time_complexity: "O(n)"
|
||||
space_complexity: "O(min(m, n))"
|
||||
complexity_explanation: |
|
||||
Time: Each character is visited at most twice (once by right, once by left).
|
||||
Space: The set holds at most min(n, m) characters where m is the charset size.
|
||||
|
||||
solutions:
|
||||
- approach_name: Sliding Window with Set (Optimal)
|
||||
is_optimal: true
|
||||
code: |
|
||||
def length_of_longest_substring(s: str) -> int:
|
||||
char_set = set()
|
||||
left = 0
|
||||
max_length = 0
|
||||
|
||||
for right in range(len(s)):
|
||||
while s[right] in char_set:
|
||||
char_set.remove(s[left])
|
||||
left += 1
|
||||
|
||||
char_set.add(s[right])
|
||||
max_length = max(max_length, right - left + 1)
|
||||
|
||||
return max_length
|
||||
explanation: |
|
||||
Expand window by moving right pointer.
|
||||
When duplicate found, shrink from left until window is valid again.
|
||||
|
||||
- approach_name: Optimized with Hash Map
|
||||
is_optimal: true
|
||||
code: |
|
||||
def length_of_longest_substring(s: str) -> int:
|
||||
char_index = {}
|
||||
left = 0
|
||||
max_length = 0
|
||||
|
||||
for right, char in enumerate(s):
|
||||
if char in char_index and char_index[char] >= left:
|
||||
left = char_index[char] + 1
|
||||
|
||||
char_index[char] = right
|
||||
max_length = max(max_length, right - left + 1)
|
||||
|
||||
return max_length
|
||||
explanation: |
|
||||
Store the last index of each character.
|
||||
Jump left pointer directly past the duplicate instead of shrinking one by one.
|
||||
Reference in New Issue
Block a user