Sweaty Imposter

Longest Substring Without Repeating Characters

MediumSliding WindowBlind 75MidOpen on LeetCodeUpdated

You're given a string s. Find the length of the longest substring in which no character appears more than once. A substring is a contiguous run of characters, so skipping characters is not allowed. Every character counts, including spaces, digits and symbols, and case matters ('a' and 'A' are different). Return only the length. An empty string has answer 0.

Examples

s = "abcabcbb" returns 3

"abc", "bca" and "cab" all have 3 distinct characters. Every substring of length 4 repeats a letter (for example "abca" repeats a), so 3 is the best.

s = "bbbbb" returns 1

Every character is b, so any substring longer than 1 repeats it. The answer is "b", length 1.

s = "pwwkew" returns 3

p0w1w2k3e4w5
"wke" has no repeated character; "kew" ties it at length 3.

"wke" (indices 2 to 4) is a longest answer, length 3. "pwke" has no repeats but skips the second w, so it is not a substring and doesn't count.

Constraints

  • 0 <= s.length <= 5 * 10^4
  • s consists of English letters, digits, symbols, and spaces.

Hints

Hint 1

Think about a contiguous range of characters that stays unique, what happens when a duplicate enters?

Hint 2
A pointer toward the approach
Hint 3
The full approach, step by step

Drill This: Your Approach First

Approach

Keep a range [left, right] with no repeats and a map from each character to the index where it was last seen. For each right, if s[right] was last seen at an index >= left, that repeat is inside the range, so jump left to one past it. Then record the new index and update the best length as right - left + 1. Each index is visited once; k is the size of the character set.

Time

O(n)

Space

O(min(n, k))

Pitfall

Only move left when the previous occurrence is inside the current range (last index >= left). Without that check left can jump backward: on "abba" the final 'a' sends left back to index 1 and you report 3 instead of 2.

Solutions

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> last = new HashMap<>();
        int left = 0, best = 0;
        for (int right = 0; right < s.length(); right++) {
            char c = s.charAt(right);
            if (last.containsKey(c) && last.get(c) >= left) {
                left = last.get(c) + 1;
            }
            last.put(c, right);
            best = Math.max(best, right - left + 1);
        }
        return best;
    }
}
Drill This