LeetCode828 Count Unique Characters of All Substrings of a Given String

this problem is belongs to one of the problems of my article: Monotonous Increasing/Decreasing Stack

so bascially, we are given a string, and we need to count the sum of (unqie_number_of_characters_in_substring1, unqie_number_of_characters_in_substring2, unqie_number_of_characters_in_substring3…). and return that number.

I believe this problem can be solved in dp. and actually, it did.
but since this problem uses the idea of monotonous stack.

we can recall that monotonous stack pair: ple and nle, ple is for us to get the closest previous of current index that less than nums[index], and nle is the closest later of current index that less than nums[index]. so we can know that how many number of subarrays that uses current nums[index] as the least number in subarray.
so how should we apply this idea to current problem?
well, rethinking current problem, which requires us to get the sum of unqiue character of all substring. so we can think of this as: we construct two mono stacks, ple and nle, and this time, ple is for us to get the e closest previous of current index that is s.charAt(index), and nle is the similiar meaning.
so ple[i] * nle[i] is the number if substring that use s.charAt(i) as the unique char, so res += 1 * ple[i] * nle[i]

so, Instead of counting all unique characters and struggling with all possible substrings,
we can count for every char in S, how many ways to be found as a unique char.
We count and sum, and it will be out answer.

but for this problem, we can’t use Stack(or can we?)
instead, we will use index[26][2] to record current char and its ple and nle.

class Solution {
    public int uniqueLetterString(String s) {
        int[][] index = new int[26][2]; 
        
        for (int i = 0; i<26; i++) {
            Arrays.fill(index[i], -1); //why we have to initialize this as -1 instead of 0? if you really understand the following for loop, this is easy to understand
        }
        
        int res = 0;
        int N = s.length();
        int mod = 1000000007;
        
        for (int i = 0; i < N; i++) {
            int c = s.charAt(i) - 'A';
            res += (i - index[c][1]) * (index[c][1] - index[c][0]) * 1 % mod; //currently, the value of index[c] is {index[c][0], index[c][1]}, so the index[c][1] meaning of this is, the closest index with current index i that they both have the same value. and index[c][0] is the second closest index
            index[c] = new int[]{index[c][1], i}; //after we using c, this place will be updated, you can see this process as a constructed process, or update process
        }
        
        //why we need to use this for loop?
        //because this is used for calculate the last segement of each char, why? bevause in the precious for loop, we only calcualte the res when there is a same char appears, but we don't calculate the number of subarrays that uses the last index of a char as the unique char. if you still don;t understand, please see the explaintion below
        for (int c = 0; c < 26; c++) {
            res += (N - index[c][1]) * (index[c][1] - index[c][0]) * 1 % mod;
        }
        return res;
        
    }
}

explaintion provided by leetcode@lee215

  1. index[26][2] record last two occurrence index for every upper characters.
  2. Initialise all values in index to -1.
  3. Loop on string S, for every character c, update its last two occurrence index to index[c].
  4. Count when loop. For example, if “A” appears twice at index 3, 6, 9 seperately, we need to count:
    For the first “A”: (6-3) * (3-(-1))"
    For the second “A”: (9-6) * (6-3)"
    For the third “A”: (N-9) * (9-6)"

and this problem can also be solved in regular dp, we will talk about that solution later.

posted @ 2020-05-25 04:18  EvanMeetTheWorld  阅读(25)  评论(0)    收藏  举报