Skip to main content

3. Longest Substring Without Repeating Characters

mediumAsked at HubSpot

HubSpot uses this sliding-window classic to test both the pattern itself and your ability to manage a moving window's state efficiently — directly applicable to deduplicating streaming event logs in their CRM activity feeds.

By Alex Chen, Founder, InterviewChamp.AI · Last verified

Source citations

Public interview reports confirming this problem appears in HubSpot loops.

  • Glassdoor (2026-Q1)HubSpot SWE candidates report Longest Substring Without Repeating Characters appearing frequently in onsite coding rounds.
  • Blind (2025-12)HubSpot threads cite this as a go-to medium problem testing sliding window and hash map together.

Problem

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

Example 1

Input
s = "abcabcbb"
Output
3

Explanation: The answer is 'abc', with the length of 3.

Example 2

Input
s = "pwwkew"
Output
3

Explanation: The answer is 'wke', not 'pwke' — the window shrinks when a duplicate 'w' is found.

Approaches

1. Sliding window with map (optimized)

Use a Map to store each character's most recent index. Move the left pointer directly to max(left, lastSeen[char] + 1) when a duplicate is found, skipping characters in O(1) instead of shrinking one by one.

Time
O(n)
Space
O(min(m,n)) where m is charset size
function lengthOfLongestSubstring(s) {
  const lastSeen = new Map(); // char -> last index
  let left = 0;
  let maxLen = 0;
  for (let right = 0; right < s.length; right++) {
    const ch = s[right];
    if (lastSeen.has(ch) && lastSeen.get(ch) >= left) {
      left = lastSeen.get(ch) + 1; // jump left past the duplicate
    }
    lastSeen.set(ch, right);
    maxLen = Math.max(maxLen, right - left + 1);
  }
  return maxLen;
}

Tradeoff: O(n) single pass, O(1) effectively for ASCII (bounded charset). The key optimization over a Set-based approach is jumping left directly to lastSeen + 1 rather than shrinking the window character by character. The guard `lastSeen.get(ch) >= left` prevents jumping backwards when the duplicate is outside the current window.

2. Sliding window with set

Maintain a Set of characters in the current window. When a duplicate is found, shrink from the left until the duplicate is removed, then expand right.

Time
O(n) amortized
Space
O(min(m,n))
function lengthOfLongestSubstring(s) {
  const window = new Set();
  let left = 0, maxLen = 0;
  for (let right = 0; right < s.length; right++) {
    while (window.has(s[right])) {
      window.delete(s[left]);
      left++;
    }
    window.add(s[right]);
    maxLen = Math.max(maxLen, right - left + 1);
  }
  return maxLen;
}

Tradeoff: Simpler to reason about but each left-pointer advance removes one character at a time — O(n) amortized but with more pointer movements than the Map approach. A good stepping stone to explain before presenting the optimized version.

HubSpot-specific tips

Frame the pattern: 'This is a variable-length sliding window — expand right, contract left on duplicates.' HubSpot interviewers want to see the Map-based jump optimization, not just the Set shrink loop. State the charset constraint: 'I'm using O(1) space for ASCII; for Unicode, the map size is bounded by code points.' They often ask what happens with an empty string (return 0) — handle it implicitly via maxLen starting at 0.

Common mistakes

  • Not guarding against lastSeen.get(ch) < left — jumping left backward corrupts the window.
  • Updating lastSeen before moving left — always move left first, then update the map.
  • Using s.indexOf(char) in the shrink loop — O(n) per step makes the overall algorithm O(n²).
  • Off-by-one in the window length: right - left + 1, not right - left.

Follow-up questions

An interviewer at HubSpot may pivot to one of these next:

  • Longest Substring with At Most K Distinct Characters (LC 340) — generalize the uniqueness constraint.
  • Minimum Window Substring (LC 76) — find the smallest window containing all characters of a pattern.
  • How would your solution change if the input is a stream of characters (no random access)?

Solve it now

Free. No sign-up. Python and JavaScript run instantly in your browser.

Output

Press Run or Cmd+Enter to execute

FAQ

Why does the Map approach need the `>= left` guard?

If a character appeared before the current window's left boundary, its stored index is stale. Jumping to it would move left backwards. The guard ensures we only use positions inside the current window.

What is the space complexity for Unicode inputs?

Bounded by the number of distinct characters in the string, which is at most O(n) in the worst case. For ASCII (128 chars) it's effectively O(1).

Does this handle spaces and special characters?

Yes — the Map/Set treats all characters uniformly by their Unicode code point. The charset is irrelevant to the algorithm.

Practice these live with InterviewChamp.AI

Drill Longest Substring Without Repeating Characters and other HubSpot interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.

Practice these live with InterviewChamp.AI →