Talentd
FleetCode
Make and follow sheets.Sign in

Count Vowels Permutation solution and explanation

HardDynamic Programming8 min read61.7% acceptanceUpdated 9 Apr 2026
Count Vowels Permutation - Dynamic Programming - Leetcode 1220 - PythonNeetCode · 11:46 · 47K viewsWatch on YouTube
9 more videos on this problem
  1. Count Vowels Permutation - Dynamic Programming - Leetcode 1220 - PythonNeetCode · 11:46 · 47K views
  2. Count Vowels Permutation | Leetcode 1220 | Live coding sessionCoding Decoded · 7:42 · 4K views
  3. Count Vowels Permutation | Recursion | Memoization | Bottom Up | GOOGLE | META | Leetcode - 1220codestorywithMIK · 48:45 · 3K views
  4. 1220 Count Vowels PermutationKelvin Chandra · 3:23 · 2K views
  5. Count Vowels Permutation | Dynamic Programming | 1220 LeetCode | Day 04CodeWithSunny · 14:37 · 2K views
  6. 1220. Count Vowels Permutation | DYNAMIC PROGRAMMING | LEETCODE HARDcode Explainer · 10:46 · 1K views
  7. LeetCode 1220. Count Vowels Permutation Solution Explained - JavaAlgorithms and Data Structures Course · 19:48 · 948 views
  8. LeetCode 1220. Count Vowels PermutationHappy Coding · 6:40 · 734 views
  9. Count Vowels Permutation | LeetCode 1220 | Coders CampCoders Camp · 11:04 · 695 views
  10. 1220. Count Vowels Permutation - Hard || Dynamic Programming || LeetCodeSagar Malhotra · 38:25 · 491 views

The problem

Given an integer n, your task is to count how many strings of length n can be formed under the following rules:

  • Each character is a lower case vowel ('a', 'e', 'i', 'o', 'u')
  • Each vowel 'a' may only be followed by an 'e'.
  • Each vowel 'e' may only be followed by an 'a' or an 'i'.
  • Each vowel 'i' may not be followed by another 'i'.
  • Each vowel 'o' may only be followed by an 'i' or a 'u'.
  • Each vowel 'u' may only be followed by an 'a'.

Since the answer may be too large, return it modulo 10^9 + 7.

Example 1:

Input: n = 1
Output: 5
Explanation: All possible strings are: "a", "e", "i" , "o" and "u".

Example 2:

Input: n = 2
Output: 10
Explanation: All possible strings are: "ae", "ea", "ei", "ia", "ie", "io", "iu", "oi", "ou" and "ua".

Example 3: 

Input: n = 5
Output: 68

Constraints:

  • 1 <= n <= 2 * 10^4

Approach overview

Problem Overview: You need to count how many strings of length n can be formed using the vowels a, e, i, o, u, while following strict transition rules between characters. Each vowel can only be followed by certain other vowels. The task is to compute the number of valid permutations modulo 1e9 + 7.

Approach 1: Dynamic Programming (O(n) time, O(n) space)

Model the problem using dynamic programming. Define dp[i][v] as the number of valid strings of length i ending with vowel v. Initialize the first position with 1 for every vowel since any vowel can start a string. For each next length, update counts based on the allowed transitions: for example a can follow e, i, or u, while e can follow a or i. Iterate from length 2 to n, applying these transitions and storing results in the DP table. The final answer is the sum of counts for all vowels at length n. This approach clearly represents the recurrence but stores the full DP table.

Approach 2: Dynamic Programming with State Tracking (O(n) time, O(1) space)

You do not actually need the entire DP table. Each step depends only on the counts from the previous step. Track five variables representing strings ending with a, e, i, o, and u. For every iteration, compute the next counts using the transition rules, then overwrite the previous state. For example the next a count equals the sum of previous e, i, and u. This effectively treats the transitions as a small state machine. The algorithm runs in linear time while using constant memory, which is typical for optimized dynamic programming problems with fixed states. The idea is closely related to state compression techniques used in graph-like transition systems.

Recommended for interviews: Interviewers expect the optimized dynamic programming approach with state tracking. Starting with the DP table demonstrates that you understand the recurrence relation and transitions. Compressing the table into five running variables shows stronger problem-solving ability and awareness of space optimization patterns common in dynamic programming problems.

Approach 1: Dynamic Programming

This approach uses dynamic programming to build up the solution by storing the number of strings of length n ending with each vowel, based on the rules provided. We use a table where each row corresponds to a length from 1 to n, and each column corresponds to a vowel. The value at each cell (i, j) represents the number of strings of length i that end with the respective vowel j.

We update this table iteratively by considering the transition rules from one vowel to another, ensuring only valid transitions contribute to the count. Finally, we sum up the counts for all vowels at length n to get the result.

def count_vowel_permutation(n):
    MOD = 10**9 + 7
    # Vowel states initialized
    dp = [1, 1, 1, 1, 1]  # Represents counts for a, e, i, o, u respectively
    for _ in range(1, n):
        dp_next = [0] * 5
        dp_next[0] = (dp[1]) % MOD  # a can follow e
        dp_next[1] = (dp[0] + dp[2]) % MOD  # e can follow a, i
        dp_next[2] = (dp[0] + dp[1] + dp[3] + dp[4]) % MOD  # i can follow a, e, o, u
        dp_next[3] = (dp[2] + dp[4]) % MOD  # o can follow i, u
        dp_next[4] = (dp[0]) % MOD  # u can follow a
        dp = dp_next
    return sum(dp) % MOD

# Usage: 
# print(count_vowel_permutation(1))  # Output: 5
# print(count_vowel_permutation(2))  # Output: 10
public class VowelPermutation {
    public int countVowelPermutation(int n) {
        int MOD = 1000000007;
        long[] dp = new long[]{1, 1, 1, 1, 1};  // a, e, i, o, u
        for (int i = 1; i < n; i++) {
            long[] dpNext = new long[5];
            dpNext[0] = (dp[1] + dp[2] + dp[4]) % MOD;  // a follows e, i, u
            dpNext[1] = (dp[0] + dp[2]) % MOD;          // e follows a, i
            dpNext[2] = (dp[1] + dp[3]) % MOD;          // i follows e, o
            dpNext[3] = dp[2] % MOD;                    // o follows i
            dpNext[4] = (dp[2] + dp[3]) % MOD;          // u follows i, o
            dp = dpNext;
        }
        long sum = 0;
        for (long x : dp) sum = (sum + x) % MOD;
        return (int) sum;
    }

    public static void main(String[] args) {
        VowelPermutation vp = new VowelPermutation();
        System.out.println(vp.countVowelPermutation(1));  // Output: 5
        System.out.println(vp.countVowelPermutation(2));  // Output: 10
    }
}

The Python code uses an array to track the number of paths ending with each vowel. In each iteration, a new array 'dp_next' is computed based on the current state of 'dp'. Each array index corresponds to a vowel, and they are updated according to the transition rules given:

  • 'a' can only follow 'e',
  • 'e' can follow 'a', 'i',
  • 'i' can't follow 'i', but can follow the others,
  • 'o' can follow 'i', 'u',
  • 'u' can follow 'a'.

After processing n steps, the result is the sum of the counts of strings ending with each vowel, modulo 10^9 + 7.

Complexity

Time Complexity: O(n), since we iterate through each position up to n.
Space Complexity: O(1), since we only keep track of the current and next states without additional memory usage.

Try this approach in the editor

Approach 2: Dynamic Programming with State Tracking

This approach is similar to the previous one but breaks down the state transitions further into distinct functions, or transitions explicitly defined between states (vowels). It effectively uses a dynamic programming table but emphasizes clear rules defining how counts from one step translate to the next.

#include <iostream>
#include <vector>

class VowelPermutation {
public:
    int countVowelPermutation(int n) {
        const int MOD = 1000000007;
        std::vector<long> dp(5, 1); // a, e, i, o, u
        for (int i = 1; i < n; ++i) {
            std::vector<long> dpNext(5);
            dpNext[0] = (dp[1] + dp[2] + dp[4]) % MOD; // a follows e, i, u
            dpNext[1] = (dp[0] + dp[2]) % MOD;        // e follows a, i
            dpNext[2] = (dp[1] + dp[3]) % MOD;        // i follows e, o
            dpNext[3] = dp[2] % MOD;                  // o follows i
            dpNext[4] = (dp[2] + dp[3]) % MOD;        // u follows i, o
            dp = dpNext;
        }
        long sum = 0;
        for (long x : dp) sum = (sum + x) % MOD;
        return sum;
    }
};

int main() {
    VowelPermutation vp;
    std::cout << vp.countVowelPermutation(1) << std::endl; // Output: 5
    std::cout << vp.countVowelPermutation(2) << std::endl; // Output: 10
    return 0;
}
function countVowelPermutation(n) {
    const MOD = 10 ** 9 + 7;
    let dp = [1, 1, 1, 1, 1]; // a, e, i, o, u
    for (let i = 1; i < n; i++) {
        let dpNext = new Array(5).fill(0);
        dpNext[0] = (dp[1] + dp[2] + dp[4]) % MOD; // a follows e, i, u
        dpNext[1] = (dp[0] + dp[2]) % MOD;        // e follows a, i
        dpNext[2] = (dp[1] + dp[3]) % MOD;        // i follows e, o
        dpNext[3] = dp[2] % MOD;                  // o follows i
        dpNext[4] = (dp[2] + dp[3]) % MOD;        // u follows i, o
        dp = dpNext;
    }
    return dp.reduce((sum, x) => (sum + x) % MOD, 0);
}

// Example usage:
// console.log(countVowelPermutation(1)); // Output: 5
// console.log(countVowelPermutation(2)); // Output: 10

The C++ code offers a slightly more verbose approach, further clarifying transitions between each vowel index state. Functional decomposition is used by specifying transition rules explicitly for each vowel state, showing how dp[i] evolves into dp[next]. This approach emphasizes clarity of state changes across each step n.

Complexity

Time Complexity: O(n) for calculations across string length iteratively.
Space Complexity: O(1), utilizing a constant array scale unrelated to n.

Try this approach in the editor

Approach 3: Dynamic Programming

Based on the problem description, we can list the possible subsequent vowels for each vowel:

a [e]
e [a|i]
i [a|e|o|u]
o [i|u]
u [a]

From this, we can deduce the possible preceding vowels for each vowel:

[e|i|u] a
[a|i]   e
[e|o]   i
[i] o
[i|o]   u

We define f[i] as the number of strings of the current length ending with the i-th vowel. If the length is 1, then f[i]=1.

When the length is greater than 1, we define g[i] as the number of strings of the current length ending with the i-th vowel. Then g[i] can be derived from f, that is:

$ g[i]= \begin{cases} f[1]+f[2]+f[4] & i=0 \ f[0]+f[2] & i=1 \ f[1]+f[3] & i=2 \ f[2] & i=3 \ f[2]+f[3] & i=4 \end{cases}

The final answer is sum_{i=0}^{4}f[i]. Note that the answer may be very large, so we need to take the modulus of 10^9+7.

The time complexity is O(n), and the space complexity is O(C). Here, n is the length of the string, and C is the number of vowels. In this problem, C=5$.

function countVowelPermutation(n: number): number {
    const f: number[] = Array(5).fill(1);
    const mod = 1e9 + 7;
    for (let i = 1; i < n; ++i) {
        const g: number[] = Array(5).fill(0);
        g[0] = (f[1] + f[2] + f[4]) % mod;
        g[1] = (f[0] + f[2]) % mod;
        g[2] = (f[1] + f[3]) % mod;
        g[3] = f[2];
        g[4] = (f[2] + f[3]) % mod;
        f.splice(0, 5, ...g);
    }
    return f.reduce((a, b) => (a + b) % mod);
}
func countVowelPermutation(n int) (ans int) {
	const mod int = 1e9 + 7
	f := make([]int, 5)
	for i := range f {
		f[i] = 1
	}
	for i := 1; i < n; i++ {
		g := make([]int, 5)
		g[0] = (f[1] + f[2] + f[4]) % mod
		g[1] = (f[0] + f[2]) % mod
		g[2] = (f[1] + f[3]) % mod
		g[3] = f[2] % mod
		g[4] = (f[2] + f[3]) % mod
		f = g
	}
	for _, x := range f {
		ans = (ans + x) % mod
	}
	return
}
Try this approach in the editor

Approach 4: Matrix Exponentiation to Accelerate Recursion

The time complexity is O(C^3 times log n), and the space complexity is O(C^2). Here, C is the number of vowels. In this problem, C=5.

const mod = 1e9 + 7;

function countVowelPermutation(n: number): number {
    const a: number[][] = [
        [0, 1, 0, 0, 0],
        [1, 0, 1, 0, 0],
        [1, 1, 0, 1, 1],
        [0, 0, 1, 0, 1],
        [1, 0, 0, 0, 0],
    ];
    const res = pow(a, n - 1);
    return res[0].reduce((a, b) => (a + b) % mod);
}

function mul(a: number[][], b: number[][]): number[][] {
    const [m, n] = [a.length, b[0].length];
    const c = Array.from({ length: m }, () => Array.from({ length: n }, () => 0));
    for (let i = 0; i < m; ++i) {
        for (let j = 0; j < n; ++j) {
            for (let k = 0; k < b.length; ++k) {
                c[i][j] =
                    (c[i][j] + Number((BigInt(a[i][k]) * BigInt(b[k][j])) % BigInt(mod))) % mod;
            }
        }
    }
    return c;
}

function pow(a: number[][], n: number): number[][] {
    let res: number[][] = [[1, 1, 1, 1, 1]];
    while (n) {
        if (n & 1) {
            res = mul(res, a);
        }
        a = mul(a, a);
        n >>>= 1;
    }
    return res;
}
const mod = 1e9 + 7

func countVowelPermutation(n int) (ans int) {
	a := [][]int{
		{0, 1, 0, 0, 0},
		{1, 0, 1, 0, 0},
		{1, 1, 0, 1, 1},
		{0, 0, 1, 0, 1},
		{1, 0, 0, 0, 0}}
	res := pow(a, n-1)
	for _, x := range res[0] {
		ans = (ans + x) % mod
	}
	return
}

func mul(a, b [][]int) [][]int {
	m, n := len(a), len(b[0])
	c := make([][]int, m)
	for i := range c {
		c[i] = make([]int, n)
	}
	for i := 0; i < m; i++ {
		for j := 0; j < n; j++ {
			for k := 0; k < len(b); k++ {
				c[i][j] = (c[i][j] + a[i][k]*b[k][j]) % mod
			}
		}
	}
	return c
}

func pow(a [][]int, n int) [][]int {
	res := [][]int{{1, 1, 1, 1, 1}}
	for n > 0 {
		if n&1 == 1 {
			res = mul(res, a)
		}
		a = mul(a, a)
		n >>= 1
	}
	return res
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Dynamic Programming

Time Complexity: O(n), since we iterate through each position up to n.
Space Complexity: O(1), since we only keep track of the current and next states without additional memory usage.

Dynamic Programming with State Tracking

Time Complexity: O(n) for calculations across string length iteratively.
Space Complexity: O(1), utilizing a constant array scale unrelated to n.

Dynamic Programming–
Matrix Exponentiation to Accelerate Recursion–

Complexity analysis

ApproachTimeSpaceWhen to Use
Dynamic Programming (DP Table)O(n)O(n)Useful for understanding the recurrence and visualizing transitions between vowels.
Dynamic Programming with State TrackingO(n)O(1)Best for interviews and production code when memory optimization matters.

Frequently asked questions

Is Count Vowels Permutation easy or hard?

Count Vowels Permutation is classified as Hard on LeetCode. The difficulty comes from recognizing the transition rules as a dynamic programming state machine and implementing the recurrence efficiently.

Count Vowels Permutation Python/Java solution

Both Python and Java implementations follow the same DP transition logic. Track counts for each vowel and update them for each position up to n while applying modulo 1e9+7 to prevent overflow.

How to solve Count Vowels Permutation in O(n)?

Track the number of valid strings ending with each vowel. At every step compute the next counts using the transition rules: a comes from e, i, u; e comes from a, i; i comes from e, o; o comes from i; u comes from i, o. Repeat for n iterations and sum the final counts.

What is the best approach for Count Vowels Permutation?

The best approach uses dynamic programming with state tracking. Maintain five counters representing strings ending in a, e, i, o, and u. Update them each step using the allowed transition rules. This runs in O(n) time and O(1) space.

Is Count Vowels Permutation asked at Google/Amazon/Meta?

This problem represents a classic dynamic programming with state transition pattern that appears in interviews at large tech companies such as Google, Amazon, and Meta. Variations of constrained string counting and DP state transitions are common interview topics.

What data structure is used in Count Vowels Permutation?

The solution primarily uses dynamic programming. Implementations typically store counts in either a DP array like dp[n][5] or five integer variables representing the current vowel states.

What is the time complexity of Count Vowels Permutation?

The optimal solution runs in O(n) time because you process each string length once and update five vowel states. Space complexity can be reduced to O(1) by keeping only the previous step’s counts instead of a full DP table.

Comments

Now write it yourselfClose this page and solve Count Vowels Permutation in the editor, without looking.
Practise Count Vowels Permutation