Skip to main content

3. Longest Substring Without Repeating Characters

mediumAsked at Atlassian

Longest Substring Without Repeating Characters is the canonical Atlassian sliding-window problem. Given a string s, return the length of the longest substring without repeating characters. Atlassian uses it to gate whether you understand the two-pointer / sliding-window pattern.

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

Source citations

Public interview reports confirming this problem appears in Atlassian loops.

  • Glassdoor (2026-Q1)Atlassian SWE-II phone-screen reports cite Longest Substring as a recurring sliding-window warm-up.
  • Blind (2025-09)Atlassian L4 candidate threads list this as the canonical string warm-up before Word Break or Minimum Window Substring.

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 length 3.

Example 2

Input
s = "bbbbb"
Output
1

Explanation: The answer is 'b'.

Example 3

Input
s = "pwwkew"
Output
3

Explanation: The answer is 'wke'. Note 'pwke' is a subsequence, not substring.

Approaches

1. Brute O(n^3) — enumerate substrings

For every (i, j) pair, check if s[i..j] is unique. Track max length.

Time
O(n^3)
Space
O(min(n, alphabet))
function lengthOfLongestSubstringBrute(s) {
  let max = 0;
  for (let i = 0; i < s.length; i++) {
    for (let j = i; j < s.length; j++) {
      const seen = new Set();
      let ok = true;
      for (let k = i; k <= j; k++) {
        if (seen.has(s[k])) { ok = false; break; }
        seen.add(s[k]);
      }
      if (ok && j - i + 1 > max) max = j - i + 1;
    }
  }
  return max;
}

Tradeoff: Times out at n=5*10^4. Useful only as the 'I see the obvious bad version' framing before sliding window.

2. Sliding window with set (O(n))

Two pointers L and R. Grow R; if s[R] is in the window set, shrink L until it isn't. Track max window length.

Time
O(n)
Space
O(min(n, alphabet))
function lengthOfLongestSubstringSet(s) {
  const seen = new Set();
  let left = 0, max = 0;
  for (let right = 0; right < s.length; right++) {
    while (seen.has(s[right])) {
      seen.delete(s[left]);
      left++;
    }
    seen.add(s[right]);
    if (right - left + 1 > max) max = right - left + 1;
  }
  return max;
}

Tradeoff: Each character enters and leaves the set at most once, so the total work is amortized O(n) despite the inner while loop. Atlassian-accepted; this is the version most candidates ship.

3. Sliding window with last-index map (optimal jump)

Track the LAST INDEX of each character. When s[R] is in the window, jump L past the previous occurrence instead of shrinking one at a time.

Time
O(n)
Space
O(min(n, alphabet))
function lengthOfLongestSubstring(s) {
  const lastIndex = new Map();
  let left = 0, max = 0;
  for (let right = 0; right < s.length; right++) {
    const ch = s[right];
    if (lastIndex.has(ch) && lastIndex.get(ch) >= left) {
      left = lastIndex.get(ch) + 1;
    }
    lastIndex.set(ch, right);
    if (right - left + 1 > max) max = right - left + 1;
  }
  return max;
}

Tradeoff: Same big-O but a single jump per repeat instead of shrinking one char at a time. Better constants, slightly subtler invariant. Atlassian Senior interviewers explicitly look for the map version; for SWE-I/II either is fine.

Atlassian-specific tips

Atlassian interviewers reward the 'left jumps over the previous occurrence' insight — it's the same trick that powers efficient text indexing. Show the set version first, then say 'I can avoid the inner shrinking loop by jumping left' and rewrite to the map version. Be ready for the Unicode follow-up: Set/Map keyed on the code-point string already handles it, but a 128-array does not.

Common mistakes

  • On the map version, jumping left = lastIndex.get(ch) + 1 unconditionally — wrong if that previous occurrence is already OUTSIDE the current window. The guard `>= left` is required.
  • Using s.indexOf() inside the loop to find the previous occurrence — that's O(n) per step and silently makes the whole thing O(n^2).
  • Returning the substring instead of the length — read the problem twice.

Follow-up questions

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

  • Longest Substring with At Most K Distinct Characters (LeetCode 340) — same window, but track distinct-char count.
  • Minimum Window Substring (LeetCode 76) — given t, return the smallest window of s containing all chars of t (with counts).
  • What if input is a stream and you must report the running max? Same window logic; emit max after each char.

Solve it now

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

Output

Press Run or Cmd+Enter to execute

FAQ

Set or map version at Atlassian?

Set version is the safer first answer because it's slightly more readable. Mention the map-jump version as the optimization. At Senior+ lead with the map version directly to score on the 'fluent in sliding window' axis.

Why does the >= left guard matter?

Because lastIndex remembers ALL occurrences, not just those inside the current window. If 'a' last appeared at index 3 but our window now starts at index 7, we should NOT jump left back to index 4 — that would re-expand the window. The guard `lastIndex.get(ch) >= left` enforces this.

Free learning resources

Curated free links for this problem.

Practice these live with InterviewChamp.AI

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

Practice these live with InterviewChamp.AI →