Facebook Pixel

2586. Count the Number of Vowel Strings in Range

EasyArrayStringCounting
Leetcode Link

Problem Description

You are given an array of strings words (0-indexed) and two integers left and right.

A vowel string is defined as a string that:

  • Starts with a vowel character ('a', 'e', 'i', 'o', or 'u')
  • Ends with a vowel character ('a', 'e', 'i', 'o', or 'u')

Your task is to count how many strings in the subarray words[left] to words[right] (inclusive) are vowel strings.

For example:

  • "apple" is a vowel string (starts with 'a', ends with 'e')
  • "orange" is a vowel string (starts with 'o', ends with 'e')
  • "bat" is NOT a vowel string (starts with 'b', which is not a vowel)
  • "end" is NOT a vowel string (ends with 'd', which is not a vowel)

The solution iterates through each word in the range [left, right] and checks if both the first character w[0] and last character w[-1] are vowels. It uses Python's in operator to check if a character exists in the string 'aeiou'. The sum() function counts how many words satisfy both conditions.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The problem asks us to count strings that meet a specific criteria within a given range. The straightforward approach is to examine each string in the specified range and check if it satisfies our conditions.

For a string to be a "vowel string", we need to verify two conditions:

  1. The first character must be a vowel
  2. The last character must be a vowel

Since we only care about strings within the range [left, right], we can slice the array to get just the elements we need: words[left : right + 1].

For each word in this range, we can access the first character using w[0] and the last character using w[-1] (Python's negative indexing makes this convenient). To check if a character is a vowel, we can use the membership test in 'aeiou', which is both concise and efficient for small sets.

The key insight is that we can combine these checks into a single boolean expression: w[0] in 'aeiou' and w[-1] in 'aeiou'. This expression evaluates to True (which has a numeric value of 1) when both conditions are met, and False (value of 0) otherwise.

By using Python's sum() function with a generator expression, we can count all the True values in one pass. This eliminates the need for explicit loops and counter variables, making the solution both elegant and efficient.

Solution Approach

The solution uses a direct simulation approach to solve the problem. We traverse through the strings in the specified range and count those that meet the vowel string criteria.

Implementation Steps:

  1. Array Slicing: Extract the relevant portion of the array using Python's slice notation words[left : right + 1]. This gives us only the strings we need to examine, from index left to index right inclusive.

  2. Vowel Checking: For each word w in the sliced array:

    • Check if the first character w[0] is in the set of vowels 'aeiou'
    • Check if the last character w[-1] is in the set of vowels 'aeiou'
    • Both conditions must be true for the word to be counted
  3. Counting with Generator Expression: The solution uses a generator expression inside the sum() function:

    sum(w[0] in 'aeiou' and w[-1] in 'aeiou' for w in words[left : right + 1])

    This expression generates a sequence of boolean values (True or False) for each word. When sum() processes these values, True is treated as 1 and False as 0, effectively counting the number of vowel strings.

Time Complexity: O(n) where n = right - left + 1 (the number of strings in the range). We visit each string in the range exactly once.

Space Complexity: O(1) as we only use a constant amount of extra space. The generator expression doesn't create an intermediate list but evaluates one element at a time.

The beauty of this solution lies in its simplicity - it directly implements what the problem asks for without any unnecessary complexity or additional data structures.

Ready to land your dream job?

Unlock your dream job with a 3-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a concrete example to understand how the solution works.

Input:

  • words = ["apple", "bat", "orange", "end", "umbrella"]
  • left = 1
  • right = 4

Step 1: Extract the subarray We need to examine words[1:5] (indices 1 through 4 inclusive):

  • Subarray: ["bat", "orange", "end", "umbrella"]

Step 2: Check each word

For "bat" (index 1):

  • First character: 'b' → Is it in 'aeiou'? No
  • Last character: 't' → Is it in 'aeiou'? No
  • Both conditions met? No → Count: 0

For "orange" (index 2):

  • First character: 'o' → Is it in 'aeiou'? Yes
  • Last character: 'e' → Is it in 'aeiou'? Yes
  • Both conditions met? Yes → Count: 1

For "end" (index 3):

  • First character: 'e' → Is it in 'aeiou'? Yes
  • Last character: 'd' → Is it in 'aeiou'? No
  • Both conditions met? No → Count: 0

For "umbrella" (index 4):

  • First character: 'u' → Is it in 'aeiou'? Yes
  • Last character: 'a' → Is it in 'aeiou'? Yes
  • Both conditions met? Yes → Count: 1

Step 3: Sum the results The generator expression produces: False, True, False, True When summed: 0 + 1 + 0 + 1 = 2

Result: The function returns 2, indicating there are 2 vowel strings in the range.

Solution Implementation

1class Solution:
2    def vowelStrings(self, words: List[str], left: int, right: int) -> int:
3        """
4        Count the number of strings that start and end with a vowel
5        within the specified range [left, right] inclusive.
6      
7        Args:
8            words: List of strings to check
9            left: Starting index of the range (inclusive)
10            right: Ending index of the range (inclusive)
11          
12        Returns:
13            Number of strings that both start and end with a vowel
14        """
15        # Define the set of vowels for checking
16        vowels = 'aeiou'
17      
18        # Initialize counter for valid strings
19        count = 0
20      
21        # Iterate through the specified range of words
22        for i in range(left, right + 1):
23            word = words[i]
24          
25            # Check if both first and last characters are vowels
26            if word[0] in vowels and word[-1] in vowels:
27                count += 1
28      
29        return count
30
1class Solution {
2    /**
3     * Counts the number of strings that start and end with a vowel
4     * within the specified range [left, right] inclusive.
5     * 
6     * @param words Array of strings to check
7     * @param left Starting index of the range (inclusive)
8     * @param right Ending index of the range (inclusive)
9     * @return Count of strings that start and end with vowels
10     */
11    public int vowelStrings(String[] words, int left, int right) {
12        int count = 0;
13      
14        // Iterate through the specified range of words
15        for (int i = left; i <= right; i++) {
16            String currentWord = words[i];
17          
18            // Check if both first and last characters are vowels
19            char firstChar = currentWord.charAt(0);
20            char lastChar = currentWord.charAt(currentWord.length() - 1);
21          
22            if (isVowel(firstChar) && isVowel(lastChar)) {
23                count++;
24            }
25        }
26      
27        return count;
28    }
29  
30    /**
31     * Checks if a character is a vowel (a, e, i, o, u).
32     * 
33     * @param c Character to check
34     * @return true if the character is a vowel, false otherwise
35     */
36    private boolean isVowel(char c) {
37        return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
38    }
39}
40
1class Solution {
2public:
3    int vowelStrings(vector<string>& words, int left, int right) {
4        // Lambda function to check if a character is a vowel
5        auto isVowel = [](char c) -> bool {
6            return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
7        };
8      
9        // Counter for strings that start and end with vowels
10        int count = 0;
11      
12        // Iterate through the specified range [left, right]
13        for (int i = left; i <= right; ++i) {
14            const string& word = words[i];
15          
16            // Check if both first and last characters are vowels
17            // If true, increment count by 1 (implicit bool to int conversion)
18            if (isVowel(word[0]) && isVowel(word[word.size() - 1])) {
19                count++;
20            }
21        }
22      
23        return count;
24    }
25};
26
1/**
2 * Counts the number of strings that start and end with a vowel within the given range
3 * @param words - Array of strings to check
4 * @param left - Starting index of the range (inclusive)
5 * @param right - Ending index of the range (inclusive)
6 * @returns Number of strings that start and end with a vowel
7 */
8function vowelStrings(words: string[], left: number, right: number): number {
9    // Initialize counter for valid strings
10    let count: number = 0;
11  
12    // Define the set of vowels to check against
13    const vowels: string[] = ['a', 'e', 'i', 'o', 'u'];
14  
15    // Iterate through the specified range of words
16    for (let index: number = left; index <= right; index++) {
17        const currentWord: string = words[index];
18      
19        // Check if both first and last characters are vowels
20        const firstChar: string = currentWord[0];
21        const lastChar: string | undefined = currentWord.at(-1);
22      
23        if (vowels.includes(firstChar) && lastChar && vowels.includes(lastChar)) {
24            count++;
25        }
26    }
27  
28    return count;
29}
30

Time and Space Complexity

Time Complexity: O(m) where m = right - left + 1

The algorithm iterates through a slice of the words list from index left to right (inclusive), which contains m = right - left + 1 elements. For each word in this range, it performs constant-time operations:

  • Accessing the first character w[0] - O(1)
  • Accessing the last character w[-1] - O(1)
  • Checking membership in the string 'aeiou' - O(1) (since the string has constant size)

Therefore, the overall time complexity is O(m).

Space Complexity: O(1)

The algorithm uses only a constant amount of extra space:

  • The generator expression doesn't create an intermediate list; it evaluates lazily
  • The sum() function accumulates the result using a single variable
  • No additional data structures are created that depend on the input size

The slicing operation words[left : right + 1] creates a view/reference rather than copying the elements, so it doesn't contribute to space complexity. Therefore, the space complexity is O(1).

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Empty String Handling

One of the most common pitfalls is not considering the case where a word in the array might be an empty string. Accessing word[0] or word[-1] on an empty string will raise an IndexError.

Problem Example:

words = ["apple", "", "orange"]
left, right = 0, 2
# This will crash when processing the empty string at index 1

Solution: Add a check for empty strings before accessing the first and last characters:

class Solution:
    def vowelStrings(self, words: List[str], left: int, right: int) -> int:
        vowels = 'aeiou'
        count = 0
      
        for i in range(left, right + 1):
            word = words[i]
          
            # Check if word is not empty before accessing characters
            if word and word[0] in vowels and word[-1] in vowels:
                count += 1
      
        return count

2. Case Sensitivity

Another pitfall is assuming all input strings are lowercase. If the input contains uppercase vowels, they won't be counted since 'aeiou' only contains lowercase characters.

Problem Example:

words = ["Apple", "Orange", "ECHO"]
# These won't be counted as vowel strings even though they should be

Solution: Convert characters to lowercase before checking:

class Solution:
    def vowelStrings(self, words: List[str], left: int, right: int) -> int:
        vowels = 'aeiou'
        count = 0
      
        for i in range(left, right + 1):
            word = words[i]
          
            if word and word[0].lower() in vowels and word[-1].lower() in vowels:
                count += 1
      
        return count

3. Single Character String Edge Case

While not necessarily a bug, it's worth noting that for single-character strings, word[0] and word[-1] refer to the same character. This means a single vowel character like "a" or "e" would be counted as a vowel string, which is correct but might not be immediately obvious.

Example:

words = ["a", "b", "e"]
# "a" and "e" are both vowel strings (start and end with the same vowel)

This behavior is usually intended, but it's important to be aware of it when testing edge cases.

Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

What is an advantages of top-down dynamic programming vs bottom-up dynamic programming?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More