Skip to main content
Back to problems
#828
Hard Algorithms

Count unique characters of all substrings of a given string

Hash Table String Dynamic Programming
53.5% acceptance
Feb 22, 2026
2251
257
Let's define a function countUniqueChars(s) that returns the number of unique characters in s. For example, calling countUniqueChars(s) if s = "LEETCODE" then "L", "T", "C", "O", "D" are the unique characters since they appear only once in s, therefore countUniqueChars(s) = 5. Given a string s, return the sum of countUniqueChars(t) where t is a substring of s. The test cases are generated such that the answer fits in a 32-bit integer. Notice that some substrings can be repeated so in this case you have to count the repeated ones too.

Solution

Rust
Time O(n * m)
Space O(n * m)
LeetCode
solution.rs
/*
 * Let's define a function countUniqueChars(s) that returns the number of unique characters in s.
 * For example, calling countUniqueChars(s) if s = "LEETCODE" then "L", "T", "C", "O", "D" are the unique characters since they appear only once in s, therefore countUniqueChars(s) = 5.
 * Given a string s, return the sum of countUniqueChars(t) where t is a substring of s. The test cases are generated such that the answer fits in a 32-bit integer.
 * Notice that some substrings can be repeated so in this case you have to count the repeated ones too.
 * Example 1:
 * Input: s = "ABC"
 * Output: 10
 * Explanation: All possible substrings are: "A","B","C","AB","BC" and "ABC".
 * Every substring is composed with only unique letters.
 * Sum of lengths of all substring is 1 + 1 + 1 + 2 + 2 + 3 = 10
 * Example 2:
 * Input: s = "ABA"
 * Output: 8
 * Explanation: The same as example 1, except countUniqueChars("ABA") = 1.
 * Example 3:
 * Input: s = "LEETCODE"
 * Output: 92
 * Constraints:
 * 1 <= s.length <= 105
 * s consists of uppercase English letters only.
 */

impl Solution {
  pub fn unique_letter_string(s: String) -> i32 {
    const MOD: i64 = 1_000_000_007;
    let bytes = s.as_bytes();
    let n = bytes.len() as i64;
    // For each char, collect positions
    let mut positions: Vec<Vec<i64>> = vec![vec![]; 26];
    for (i, &b) in bytes.iter().enumerate() {
      positions[(b - b'A') as usize].push(i as i64);
    }
    let mut ans: i64 = 0;
    for pos in &positions {
      let m = pos.len();
      for j in 0..m {
        let prev = if j == 0 { -1 } else { pos[j-1] };
        let next = if j + 1 == m { n } else { pos[j+1] };
        ans = (ans + (pos[j] - prev) * (next - pos[j])) % MOD;
      }
    }
    ans as i32
  }
}