↓Skip to main content
  1. LeetCode/

LeetCode 809: Expressive Words

·3 mins· ·
LeetCode Medium Two-Pointers String Array
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: medium First Attempt: 2026-01-31

  • Submissions: Runtime Error → Wrong Answer ×2 → Accepted

Approach
#

View a string as runs of equal characters, e.g. "heeellooo" is h1 e3 l2 o3. word can stretch into s when both have the same number of runs and every run:

  • has the same character;
  • has the same length, or the run in s has length >= 3 and >= the word’s run (runs can only be extended to 3 or more, never shortened).

Two pointers walk s and word, each consuming a whole run per step, and compare lengths. After the loop both strings must be fully consumed, or one side has leftover runs.

My Attempts
#

Every mistake here was in the termination condition:

VersionProblem
Attempt 1, REThe loop checked only left < n, so once word ran out it still read word[right]. s = "aab", word = "aa" raises IndexError
Attempt 2, WAChanged to left < n and right < m but returned True after the loop without checking leftovers in s. The same "aab" / ["aa"] returned 1; the answer is 0
Attempt 3, WAAdded left == n but not a check for leftovers in word. s = "abc", word = "abcd" returned 1; the answer is 0

Requiring left == n and right == m passed.

Solution
#

class Solution:
    def expressiveWords(self, s: str, words: List[str]) -> int:
        def run_end(t: str, i: int) -> int:           # end (exclusive) of the run starting at i
            j = i
            while j < len(t) and t[j] == t[i]:
                j += 1
            return j

        def stretchy(word: str) -> bool:
            i = j = 0
            while i < len(s) and j < len(word):
                if s[i] != word[j]:
                    return False
                ni, nj = run_end(s, i), run_end(word, j)
                len_s, len_w = ni - i, nj - j
                if len_s != len_w and (len_s < 3 or len_s < len_w):
                    return False
                i, j = ni, nj
            return i == len(s) and j == len(word)

        return sum(stretchy(w) for w in words)

Complexity
#

Time O(len(s) · number of words + total length of words), space O(1).

Mistakes to Avoid
#

  • Driving the loop by one string’s length only: the other may run out first and go out of range.
  • Not checking that both strings are consumed at the end.
  • Getting the length rule backwards: the run in s may be longer, never shorter than in word.

Interview Explanation
#

I treat strings as runs of equal characters. Two pointers each consume a whole run and compare character and length: equal lengths are fine; otherwise the run in s must be at least 3 and no shorter than in word. After the loop, both strings must be fully consumed. Each word is one linear scan.

Related

LeetCode 1989: Maximum Number of People That Can Be Caught in Tag
·3 mins
LeetCode Medium Two-Pointers Greedy Array
LeetCode 1989 note: process the “it” players left to right, each catching the leftmost uncaught person in range, with a right-only pointer to the next candidate
LeetCode 1471: The k Strongest Values in an Array
·2 mins
LeetCode Medium Two-Pointers Sorting Array
LeetCode 1471 note: after sorting, the value farthest from the median is always at one of the ends, so converging pointers pick the stronger end k times
LeetCode 2563: Count the Number of Fair Pairs
·3 mins
LeetCode Medium Two-Pointers Sorting Binary-Search Array
LeetCode 2563 note: split “sum in [lower, upper]” into “sum <= upper” minus “sum <= lower - 1”, and count each with converging pointers over the sorted array in O(n)
LeetCode 1498: Number of Subsequences That Satisfy the Given Sum Condition
·2 mins
LeetCode Medium Two-Pointers Sorting Binary-Search Array
LeetCode 1498 note: only the minimum and maximum matter, so order does not and we can sort; fixing nums[left] as the minimum, the elements between are free, giving 2^(right - left) choices
LeetCode 1616: Split Two Strings to Make Palindrome
·3 mins
LeetCode Medium Two-Pointers String Greedy
LeetCode 1616 note: greedily match a’s prefix against b’s suffix from the outside in; the leftover middle must be a palindrome entirely within a or b, and both directions need checking
LeetCode 1750: Minimum Length of String After Deleting Similar Ends
·3 mins
LeetCode Medium Two-Pointers String
LeetCode 1750 note: when both ends match, each side eats its whole run of that character; a string of one repeated character can be deleted entirely