Description Link to heading

828. Count Unique Characters of All Substrings of a Given String (Hard)

Solution Link to heading

DP Link to heading

This problem can be easily solved using dynamic programming. Let’s define $dp[i]$ as the sum of countUniqueChar(t) values for substrings $t$ ending at $s[i]$. The next step is to find the recurrence relation:

Suppose the character corresponding to $s[i]$ is $c$. For substrings ending at $s[i-1]$, if the substring does not contain $c$, then the countUniqueChar value for the substring ending at $s[i]$ is equal to the value for the substring ending at $s[i-1]$ (i.e., without $c$) plus $1$. If the substring contains one $c$, then the countUniqueChar value for the substring ending at $s[i]$ is equal to the value for the substring ending at $s[i-1]$ minus $1$. If the substring contains two $c$, then the countUniqueChar values for the substrings ending at $s[i]$ and $s[i-1]$ are equal.

We maintain a vector<pair<int, int>> left_same, where left_same[i].second represents the largest index less than $i$ that contains the same character as $s[i]$ and left_same[i].first$ represents the second largest index. Note that the pair` needs to be initialized as $\lbrace -1, -1\rbrace$.

Contribution method Link to heading

We can also use the contribution method to calculate the number of substrings that include $s[i]$ in their countUniqueChar value.

Code Link to heading

DP Link to heading

class Solution {
  public:
    int uniqueLetterString(string s) {
        int n = s.size();
        vector<int> arr(26, -1);
        vector<pair<int, int>> left_same(n, {-1, -1});
        for (int i = 0; i < n; ++i) {
            if (arr[s[i] - 'A'] != -1) {
                left_same[i].first = left_same[arr[s[i] - 'A']].second;
                left_same[i].second = arr[s[i] - 'A'];
            }
            arr[s[i] - 'A'] = i;
        }
        vector<int> dp(n);
        dp[0] = 1;
        int sum = 1;
        for (int i = 1; i < n; ++i) {
            dp[i] = dp[i - 1] + i - left_same[i].second - (left_same[i].second - left_same[i].first);
            sum += dp[i];
        }
        return sum;
    }
};

Contribution method Link to heading

class Solution {
  public:
    int uniqueLetterString(string s) {
        vector<vector<int>> same(26);
        int n = s.size();
        for (int i = 0; i < n; ++i) {
            int idx = s[i] - 'A';
            same[idx].push_back(i);
        }
        int res = 0;
        for (int i = 0; i < 26; ++i) {
            for (int j = 0; j < same[i].size(); ++j) {
                int left = 0, right = 0;
                if (j == 0) {
                    left = same[i][j] + 1;
                } else {
                    left = same[i][j] - same[i][j - 1];
                }
                if (j == same[i].size() - 1) {
                    right = n - same[i][j];
                } else {
                    right = same[i][j + 1] - same[i][j];
                }
                res += left * right;
            }
        }
        return res;
    }
};