Before attempting this problem, you should be comfortable with:
A word is a "vowel string" if it starts and ends with a vowel (a, e, i, o, u). For each query, we need to count how many words in the given range satisfy this condition. The straightforward approach is to iterate through the range for each query and check each word.
(start, end):0.start to end:class Solution:
def vowelStrings(self, words: List[str], queries: List[List[int]]) -> List[int]:
vowels = set("aeiou")
res = []
for start, end in queries:
cnt = 0
for i in range(start, end + 1):
if words[i][0] in vowels and words[i][-1] in vowels:
cnt += 1
res.append(cnt)
return resWhere is the number of words, and is the number of queries.
The brute force approach recomputes the count for overlapping or similar ranges repeatedly. We can precompute a prefix sum array where prefix[i] stores the count of vowel strings from index 0 to i-1. Then any range query (l, r) can be answered in O(1) time as prefix[r+1] - prefix[l].
n+1, initialized to 0.i:prefix[i+1] = prefix[i].prefix[i+1].(l, r):prefix[r+1] - prefix[l].class Solution:
def vowelStrings(self, words: List[str], queries: List[List[int]]) -> List[int]:
vowel_set = set("aeiou")
prefix_cnt = [0] * (len(words) + 1)
prev = 0
for i, w in enumerate(words):
if w[0] in vowel_set and w[-1] in vowel_set:
prev += 1
prefix_cnt[i + 1] = prev
res = [0] * len(queries)
for i, q in enumerate(queries):
l, r = q
res[i] = prefix_cnt[r + 1] - prefix_cnt[l]
return resWhere is the number of words, and is the number of queries.
Instead of using a hash set to check vowels, we can use a bitmask. Since there are only 5 vowels and 26 letters, we can represent which characters are vowels using a single integer where bit i is set if the character at position i ('a' + i) is a vowel. Checking if a character is a vowel becomes a simple bitwise AND operation.
'a', 'e', 'i', 'o', 'u'.true, increment the prefix sum.(l, r):prefix[r+1] - prefix[l].class Solution:
def vowelStrings(self, words: List[str], queries: List[List[int]]) -> List[int]:
vowels = sum(1 << (ord(c) - ord('a')) for c in "aeiou")
prefix = [0]
for w in words:
prefix.append(prefix[-1])
if (1 << (ord(w[0]) - ord('a'))) & vowels and (1 << (ord(w[-1]) - ord('a'))) & vowels:
prefix[-1] += 1
return [prefix[r + 1] - prefix[l] for l, r in queries]Where is the number of words, and is the number of queries.
A classic mistake is using prefix[r] - prefix[l] instead of prefix[r + 1] - prefix[l]. The prefix array is 1-indexed to allow easy range queries, so the right endpoint needs the +1 offset.
# Incorrect - excludes the element at index r
res[i] = prefix[r] - prefix[l]
# Correct - includes the element at index r
res[i] = prefix[r + 1] - prefix[l]A vowel string must start AND end with a vowel. Checking only one condition will count words that should not be included.
# Incorrect - only checks starting character
if words[i][0] in vowels:
cnt += 1
# Correct - checks both first and last characters
if words[i][0] in vowels and words[i][-1] in vowels:
cnt += 1When using a bitmask or set for vowels, omitting one of the five vowels (a, e, i, o, u) leads to incorrect results. This is especially common when manually constructing the bitmask.
# Incorrect - missing 'u'
vowels = set("aeio")
# Correct - all five vowels included
vowels = set("aeiou")