Count Vowel Strings in Ranges
Problem
You are given a 0-indexed array of strings words and a 2D array of integers queries.
Each query queries[i] = [li, ri] asks us to find the number of strings present in the range li to ri (both inclusive) of words that start and end with a vowel.
Return an arrayans of sizequeries.length , whereans[i]is the answer to theith query.
Note that the vowel letters are 'a', 'e', 'i', 'o', and 'u'.
Examples
Example 1:
Input: words = ["aba","bcb","ece","aa","e"], queries = [[0,2],[1,4],[1,1]]
Output: [2,3,0]
Explanation: The strings starting and ending with a vowel are "aba", "ece", "aa" and "e".
The answer to the query [0,2] is 2 (strings "aba" and "ece").
to query [1,4] is 3 (strings "ece", "aa", "e").
to query [1,1] is 0.
We return [2,3,0].
Example 2:
Input: words = ["a","e","i"], queries = [[0,2],[0,1],[2,2]]
Output: [3,2,1]
Explanation: Every string satisfies the conditions, so we return [3,2,1].
Constraints:
1 <= words.length <= 1051 <= words[i].length <= 40words[i]consists only of lowercase English letters.sum(words[i].length) <= 3 * 1051 <= queries.length <= 1050 <= li <= ri < words.length
Solution
We need to determine the number of strings that start and end with a vowel for each given query.
Video explanation
Here is the video explaining this method in detail. Please check it out:
<div class="youtube-embed"><iframe src="https://www.youtube.com/embed/-ByDl5QvMyE" frameborder="0" allowfullscreen></iframe></div>
Method 1 - Naive
A direct approach is to iterate through each query and count the valid strings in the specified range.
Here is the approach:
- Iterate over Queries: For each query, iterate through the range of words specified and count how many meet the condition.
- Return Result: Collect answers for all queries and return them.
Code
Java
class Solution {
private boolean isVowel(char c) {
return "aeiou".indexOf(c) != -1;
}
private boolean isVowelStartEnd(String word) {
return isVowel(word.charAt(0)) && isVowel(word.charAt(word.length() - 1));
}
public int[] vowelStrings(String[] words, int[][] queries) {
int[] ans = new int[queries.length];
for (int i = 0; i < queries.length; i++) {
int l = queries[i][0];
int r = queries[i][1];
int count = 0;
for (int j = l; j <= r; j++) {
if (isVowelStartEnd(words[j])) {
count++;
}
}
ans[i] = count;
}
return ans;
}
}
Python
class Solution:
def vowelStrings(self, words: List[str], queries: List[List[int]]) -> List[int]:
def is_vowel(c: str) -> bool:
return c in 'aeiou'
def is_vowel_start_end(word: str) -> bool:
return is_vowel(word[0]) and is_vowel(word[-1])
ans: List[int] = []
for l, r in queries:
count = sum(1 for word in words[l:r+1] if is_vowel_start_end(word))
ans.append(count)
return ans
Complexity
- ⏰ Time complexity:
O(n * q), whereqis the number of queries, andnis number of words. As for each query, we might need to scan the entire range specified, leading toO(n * q) - 🧺 Space complexity:
O(1)
Method 2 - Using Prefix Sum
To efficiently solve the problem, we can pre-calculate the number of strings that start and end with a vowel up to each index and store these counts in an array. This technique allows us to answer any query in constant time (O(1)).
Using a prefix sum array, we store the cumulative count of vowel-strings up to any given index i. For any range (i, j), the number of valid strings can be quickly found using the formula:
This approach transforms the problem, enabling us to quickly answer queries about any specified range without repeatedly counting, thus improving efficiency.
Approach
-
We use a prefix sum array, where each element at index
istores the total number of vowel-strings from the start up to indexi-1.- For eg. for
["aba","bcb","ece","aa","e"]for input array, we check if they start with vowel and end with it ⇨[1, 0, 1, 1, 1](1 means it starts and end with vowel) - and prefix sum will be
[0, 1, 0, 2, 3, 4]
- For eg. for
-
Then, we run the queries on the prefix sum. For each
query[l, r], our answer will beprefixSum[r + 1] - prefixSum[l].
Code
Java
class Solution {
public int[] vowelStrings(String[] words, int[][] queries) {
Set<Character> vowels = Set.of('a', 'e', 'i', 'o', 'u');
int n = words.length;
int[] prefixSum = new int[n + 1];
for (int i = 0; i < n; i++) {
prefixSum[i + 1] = prefixSum[i];
String word = words[i];
if (vowels.contains(word.charAt(0)) && vowels.contains(word.charAt(word.length() - 1))) {
prefixSum[i + 1]++;
}
}
int[] ans = new int[queries.length];
for (int i = 0; i < queries.length; i++) {
int l = queries[i][0];
int r = queries[i][1];
ans[i] = prefixSum[r + 1] - prefixSum[l];
}
return ans;
}
}
Python
class Solution:
def vowelStrings(self, words: List[str], queries: List[List[int]]) -> List[int]:
vowels = {'a', 'e', 'i', 'o', 'u'}
n = len(words)
prefix_sum = [0] * (n + 1)
for i in range(n):
prefix_sum[i + 1] = prefix_sum[i]
word = words[i]
if word[0] in vowels and word[-1] in vowels:
prefix_sum[i + 1] += 1
ans: List[int] = []
for l, r in queries:
ans.append(prefix_sum[r + 1] - prefix_sum[l])
return ans
Complexity
- ⏰ Time complexity:
O(n + q) - 🧺 Space complexity:
O(n)for usingprefix sumarray