Skip to main content

Leetcode 3: Longest Substring Without Repeating Characters

 

Leetcode Link


1. Problem Statement (Simple Explanation)


  • You are given a string s.

  • You need to find the length of the longest substring of s that does not contain any repeated characters.

  • A substring is a contiguous sequence of characters in the string.

  • You must return an integer length, not the substring itself.


2. Examples


Example 1

  • Input: s = "abcabcbb"

  • Output: 3

  • Explanation:

Some substrings without repeating characters: "abc", "bca", "cab"The longest length is 3.

Example 2

  • Input: s = "bbbbb"

  • Output: 1

  • Explanation:

All substrings that are valid are just "b".

The longest length is 1.

Example 3

  • Input:   s = "pwwkew"

  • Output:   3

  • Explanation:

Possible substrings without repetition: "pw", "wke", "kew".

"wke" or "kew" have length 3.

"pwke" is not valid because it’s not contiguous in the original string (p and k are separated by ww).

Constraints

  • 0≤len(s)≤5×104

  • s consists of English letters, digits, symbols, and spaces.


3. Approach 1 – Brute Force (Check All Substrings)


Intuition

  • Generate all possible substrings.

  • For each substring, check if all characters are unique.

  • Track the maximum length of such substrings.

  • This is easy to understand but too slow for large strings.


Algorithm (Step-by-Step)

  1. Let n = len(s), maxLen = 0.

  2. For every starting index i from 0 to n - 1:

    1. Use a set to track characters in the current substring.

    2. For every ending index j from i to n - 1:

      1. If s[j] is already in the set, stop (this substring now has a duplicate).

      2. Otherwise, add s[j] to the set.

      3. Update maxLen = max(maxLen, j - i + 1).

  3. Return maxLen.


Pseudo-code (Brute Force)


  • The function lengthOfLongestSubstring(s) finds the length of the longest substring with all unique characters using a simple double-loop strategy.

  • It initializes maxLen = 0 and iterates over every possible start index i.

  • For each i, it creates an empty seen set to track characters in the current substring.

  • The inner loop extends the substring from j = i onward:

    • If s[j] is already in seen, a duplicate is encountered, so the inner loop stops—no longer unique substring can continue from i.

    • Otherwise, it adds s[j] to seen and updates maxLen with the current substring length j - i + 1.

  • By the end, maxLen holds the maximum length found.


Time and Space Complexity

Time: O(n2)

  • because we may examine all substrings.

Space (extra): O(k)

  • where k is the size of the character set (at most O(n), practically bounded).

  • This will TLE for large inputs and is not the optimal solution.


4. Approach 2 – Sliding Window with Hash Set (O(n))


This is the classic and intuitive optimal approach.


Intuition

  • We maintain a sliding window [left, right] that always represents a substring with no duplicate characters. We expand the window to the right as long as it stays valid; when we see a duplicate, we shrink from the left until the duplicate is removed.

  • Think of it as:

  • right moves forward character by character.

  • For each character:

    • If it’s not in the current window → expand the window.

    • If it is in the current window → shrink from the left until that character is removed.

  • We track the longest window length that remained valid.


Algorithm (Step-by-Step)

  1. Initialize:

    1. left = 0

    2. maxLen = 0

    3. an empty set seen to store characters currently in the window.

  2. For right from 0 to n - 1:

    1. While s[right] is already in seen:

      1. Remove s[left] from seen.

      2. Increment left (left++).

    2. Add s[right] to seen.

    3. Window [left, right] is now valid (no duplicates).

    4. Update:

  3. maxLen=max(maxLen,right-left+1)

  4. Return maxLen.


Pseudo-code (Sliding Window + Set)


  • This function computes the length of the longest substring without repeating characters using a sliding window with two pointers.

  • left and right define the current window [left, right].

  • A set seen stores the characters currently in the window, ensuring uniqueness.

  • As right moves from 0 to n-1, we attempt to include s[right].

    • If s[right] is already in seen, the window is invalid (has a duplicate).

    • To fix this, we shrink from the left: repeatedly remove s[left] from seen and increment left until the duplicate is gone. 

    • This guarantees the window always contains unique characters.

  • Once valid, we add s[right] to seen and update maxLen with the window size right - left + 1.


Time and Space Complexity

Time: O(n)

  • Each character is added to the set at most once and removed at most once.

Space: O(k)

  • where k is the size of the character set (at most min(n, 256) depending on encoding).


5. Approach 3 – Sliding Window with Index Map (Also O(n))


This is an optimization that often appears in editorial solutions.


Intuition

  • Instead of shrinking the window one step at a time, we jump the left pointer using a map of last seen positions.

  • Maintain a map lastIndex[ch] = last index where ch appeared + 1.

  • When we see a character s[right]:

    • If it was seen before inside the current window, we move left to max(left, lastIndex[s[right]]).

  • This keeps the window always valid and doesn’t require a while loop.


Algorithm (Step-by-Step)

  1. Initialize:

    1. left = 0

    2. maxLen = 0

    3. empty map lastIndex

  2. For right from 0 to n - 1:

    1. Let ch = s[right].

    2. If ch is in lastIndex:

      1. Set:

  3. left=max(left,lastIndex[ch])

  4. Update:

    1. lastIndex[ch] = right + 1 (store next valid position)

  5. Update:

  6. maxLen=max(maxLen,right-left+1)

  7. Return maxLen.


Pseudo-code (Sliding Window + Map)


  • This function finds the length of the longest substring without repeating characters using a sliding window and a hash map (lastIndex) that tracks each character’s most recent position.

  • left and right bound the current window.

  • For each character ch = s[right], if ch has been seen, we may need to move left forward to avoid duplicates.
    Instead of incrementing step-by-step, we jump:
    left = max(left, lastIndex[ch]).
    Here, lastIndex[ch] stores the next valid start after the previous occurrence (hence right + 1 when updating).

  • We then record lastIndex[ch] = right + 1 and update
    maxLen = max(maxLen, right - left + 1).

  • This guarantees the window [left, right] always contains unique characters and never moves left backward.


Complexity

    Same as previous optimized approach:

    Time: O(n)

    Space: O(k)

  • You can choose either set-based or map-based version for your main explanation.

  • The map-based one is slightly more elegant and common in editorial solutions.


6. Java code


7. C code


Here we’ll use an array of size 256 for ASCII-like characters.



8. C++ code



9. Python code



10. JavaScript code:





Comments

Popular posts from this blog

Leetcode 1: Two Sum

  Leetcode Link: https://leetcode.com/problems/two-sum/ 1. Problem Statement (Simple Explanation) You are given: An array of integers nums An integer target You need to  return the indices of two numbers in the array  such that: Conditions: Each input has  exactly one solution . You  cannot use the same element twice . You can return the answer in  any order . 2. Examples Example 1 Input:                                    nums = [2, 7, 11, 15], target = 9 Output:                                 [0, 1] Explanation:                     nums[0]+nums[1]=2+7=9              So we return [0, 1]. Example 2 Input:           ...

Leetcode 2: Add Two Numbers

Leetcode Link: https://leetcode.com/problems/add-two-numbers/ 1. Problem Statement (Simple Explanation) You are given  two non-empty linked lists , l1 and l2, that represent two non-negative integers. Each node contains a  single digit . The digits are stored in  reverse order  (i.e., the 1’s digit is at the head). You need to  add the two numbers  and return the  sum as a linked list , also in reverse order. You can assume: There are  no leading zeros , except when the number itself is 0. 2. Examples Example 1 Input:                l1 = [2,4,3]                l2 = [5,6,4]           Interpreting linked lists as numbers (reverse order): l1 represents 342 l2 represents 465 Output:                [7,0,8] Explanation:        ...