↓Skip to main content
  1. LeetCode/

LeetCode 2781: Length of the Longest Valid Substring

·3 mins· ·
LeetCode Hard Sliding-Window Hash-Table String Trie
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: hard First Attempt: 2026-01-14

  • Submissions: WA ×2 → AC → TLE → WA → AC ×2 (the Trie version was written on 2026-01-15)

Approach
#

A window [left, right] is valid ⇔ it contains no forbidden word. Adding a character on the right creates new substrings that all end at right, so only suffixes ending at right need checking.

Forbidden words have at most 10 characters, so check suffixes of length 1 to 10:

  • Check from short to long (start i moving left from right); the first forbidden suffix has the rightmost start.
  • Move the left end to i + 1 and break: a longer forbidden word starts further left, and moving there would not be enough.

A suffix may not start before left (those characters are already outside the window).

My Attempts
#

Neither of the first two versions had a break. Checking short to long, a short forbidden word pushed left to i + 1, then a longer one set left to a smaller i + 1, moving the left end backward so the window again contained the short word.

For word = "baba", forbidden = ["a", "ba"], any substring with a is invalid, so the answer is 1 ("b"). At right = 1, "a" set left = 2, then "ba" set left back to 1, leaving the forbidden "a" in the window. At right = 2, "ab" then counted as valid, and both versions returned 2.

Adding break passed. I later rewrote it with a reversed Trie: the first try hit TLE from a missing right += 1, and the second got WA from the same missing break.

Solution
#

class Solution:
    def longestValidSubstring(self, word: str, forbidden: List[str]) -> int:
        banned = set(forbidden)
        max_len = max(map(len, forbidden))         # at most 10
        left = best = 0
        for right in range(len(word)):
            for i in range(right, max(left, right - max_len + 1) - 1, -1):
                if word[i:right + 1] in banned:
                    left = i + 1                   # the shortest match starts furthest right
                    break
            best = max(best, right - left + 1)
        return best

Trie version: insert forbidden words reversed, walk left from right while descending the Trie, stop when there is no edge, and on an end marker push left and break. It avoids slicing substrings.

Complexity
#

Time O(n · L^2) (up to L = 10 suffixes per right end, each slice and hash O(L)); the Trie version is O(n · L). Space is the total length of the forbidden words.

Mistakes to Avoid
#

  • No break after a match: a longer forbidden word drags the left end back.
  • Checking suffix starts before left: those are outside the window.

Interview Explanation
#

A new character only creates substrings ending at it, and forbidden words are at most 10 long, so each right end checks just the last 10 suffixes. Checking short to long, the first match has the rightmost start, so I move the left end past it and stop, since a longer match would drag the left end back. Time O(n · 10^2), and a reversed Trie avoids the slicing.

Related

LeetCode 2953: Count Complete Substrings
·3 mins
LeetCode Hard Sliding-Window Hash-Table String
LeetCode 2953 note: split where neighboring letters differ by more than 2; in each segment enumerate the number of distinct letters d, slide a fixed window of d × k, and track how many letters appear exactly k times
LeetCode 2009: Minimum Number of Operations to Make Array Continuous
·2 mins
LeetCode Hard Sliding-Window Hash-Table Binary-Search Array
LeetCode 2009 note: the result is n consecutive integers; after deduplicating and sorting, a sliding window finds the most distinct values within a span of n - 1, and the rest must change
LeetCode 2516: Take K of Each Character From Left and Right
·2 mins
LeetCode Medium Sliding-Window Hash-Table String
LeetCode 2516 note: taking from both ends leaves a middle block in which each letter may appear at most total − k times; find the longest such window
LeetCode 1016: Binary String With Substrings Representing 1 To N
·3 mins
LeetCode Medium Sliding-Window String Bit-Manipulation Hash-Table
LeetCode 1016 note: s has at most 1000 characters, so there are few substrings of any fixed length and a large n must be False; checking from n downward fails fast, or extend up to 30 bits from each start to collect every value <= n
LeetCode 2156: Find Substring With Given Hash Value
·3 mins
LeetCode Hard Sliding-Window Rolling-Hash String
LeetCode 2156 note: the first character has weight p^0, so sliding right to left needs only multiply by p, add the new character, and subtract the outgoing one times p^k; the modulus may not be prime, so no modular inverse
LeetCode 3694: Distinct Points Reachable After Substring Removal
·2 mins
LeetCode Medium Sliding-Window Prefix-Sum Hash-Table String
LeetCode 3694 note: the endpoint is the total displacement minus the removed segment’s displacement; a length-k window tracks that segment and each endpoint goes into a set