Stage 4: Advanced Techniques·Combinatorics & Counting
Hard#25147 min readMathCombinatoricsModular ArithmeticLeetCode

Count Anagrams

Multinomial coefficient with modular inverse

Multinomial coefficients. Precompute factorial + modular inverse.

Published Apr 16, 2026

Problem

Given a string s of lowercase letters separated by single spaces, return the number of distinct strings that are anagrams of s, modulo 10^9 + 7.

An anagram of s must have the same words (same positions), but each word can be independently rearranged. The total count is the product of the distinct permutations of each word.

Input
s = "too hot"
Output
18
Explanation
'too' has 3!/2! = 3 anagrams. 'hot' has 3!/1! = 6. Product = 18.
Input
s = "aa"
Output
1
Explanation
'aa' has only one arrangement.

Intuition

For a single word of length L with character frequencies c_1, c_2, ..., c_26, the number of distinct permutations is the multinomial coefficient: L! / (c_1! * c_2! * ... * c_26!).

Since MOD = 10^9 + 7 is prime, division becomes multiplication by the modular inverse: a / b mod p = a * b^(p-2) mod p (Fermat's little theorem).

The total answer is the product of multinomial coefficients across all words.

Approach

Brute Permutation

TimeO(Σ L_i!)
SpaceO(L)

Generate all permutations of each word, deduplicate, count. Only feasible for very short words.

impl Solution {
    pub fn count_anagrams(s: String) -> i32 {
        const MOD: i64 = 1_000_000_007;
        let mut total: i64 = 1;
        for word in s.split(' ') {
            let mut chars: Vec<u8> = word.bytes().collect();
            chars.sort();
            let mut count: i64 = 1;
            loop {
                // next_permutation
                let n = chars.len();
                let mut i = n.wrapping_sub(2);
                while i < n && chars[i] >= chars[i + 1] {
                    if i == 0 { break; }
                    i = i.wrapping_sub(1);
                }
                if i >= n || (i == 0 && chars[0] >= chars[1]) { break; }
                let mut j = n - 1;
                while chars[j] <= chars[i] { j -= 1; }
                chars.swap(i, j);
                chars[i + 1..].reverse();
                count = 1;
            }
            total= total * count % MOD;
        }
        total as i32
    }
}
Rust · runnable

Multinomial with Modular Inverse

TimeO(L)
SpaceO(L)
Recommended

Precompute factorials and inverse factorials up to L (total string length). For each word, multiply the running product by len! and divide by each freq!.

impl Solution {
    pub fn count_anagrams(s: String) -> i32 {
        const MOD: i64 = 1_000_000_007;

        fn mod_pow(mut base: i64, mut exp: i64, m: i64) -> i64 {
            let mut result = 1i64;
            base %= m;
            while exp > 0 {
                if exp & 1 == 1 {
                    result = result * base % m;
                }
                exp >>= 1;
                base = base * base % m;
            }
            result
        }

        let n = s.len();
        let mut fact = vec![1i64; n + 1];
        for i in 1..=n {
            fact[i] = fact[i - 1] * i as i64 % MOD;
        }
        let mut inv_fact = vec![1i64; n + 1];
        inv_fact[n] = mod_pow(fact[n], MOD - 2, MOD);
        for i in (0..n).rev() {
            inv_fact[i] = inv_fact[i + 1] * (i + 1) as i64 % MOD;
        }

        let mut ans: i64 = 1;
        for word in s.split(' ') {
            let mut freq = [0usize; 26];
            for b in word.bytes() {
                freq[(b - b'a') as usize] += 1;
            }
            ans = ans * fact[word.len()] % MOD;
            for &f in &freq {
                ans = ans * inv_fact[f] % MOD;
            }
        }

        ans as i32
    }
}
Rust · runnable

Trace

s = "too hot". Total length L = 7 (including space is irrelevant; we process per word).

wordlenfreqmultinomialrunning product
too3t:1, o:23!/(1!·2!) = 33
hot3h:1, o:1, t:13!/(1!·1!·1!) = 618

Edge cases

  • Single character word1!/1! = 1. No contribution.
  • All same lettersn!/n! = 1.
  • All distinct lettersn!/1^n = n!.
  • Very long string — total length up to 10^5; precomputed factorials handle it in O(L).

Takeaway

The multinomial coefficient is the go-to formula for "distinct arrangements of items with repeats." The modular-inverse technique (a^(p-2) mod p via Fermat) is a fundamental toolkit item for competitive and production math — it shows up in probability, combinatorics, and cryptographic primitives alike.

More in Combinatorics & Counting