Unique Letter String LT828

A character is unique in string S if it occurs exactly once in it.

For example, in string S = "LETTER", the only unique characters are "L" and "R".

Let's define UNIQ(S) as the number of unique characters in string S.

For example, UNIQ("LETTER") =  2.

Given a string S with only uppercases, calculate the sum of UNIQ(substring) over all non-empty substrings of S.

If there are two or more equal substrings at different positions in S, we consider them different.

Since the answer can be very large, return the answer modulo 10 ^ 9 + 7.

Idea 1. Dynamic programming, it's a bit tricky, need to store last two indexes for each char appears in the array, assume dp[i] is the number of unique characters ending at s[i]

dp[i] = dp[i-1] + (i - last[s[i]]) - (last[s[i]] - 2ndLast[s[i]]))

ABCBDAB

i = 0, {A}, dp[0] = 1

i = 1, {AB, B}, dp[1] = 3

i = 2, {ABC, BC, C}, dp[2] = 6

i = 3, {ABCB, BCB, CB, B}, dp[3] = 6 = dp[2] + (3 - 1) -(1 - (-1)) = 6

Time complexity: O(n)

Space complexity: O(n) or O(26)

 1 class Solution {
 2     public int uniqueLetterString(String S) {
 3         int[] last = new int[26];
 4         int[] secondLast = new int[26];
 5         Arrays.fill(last, -1);
 6         Arrays.fill(secondLast, -1);
 7         
 8         int dp = 0;
 9         int result = 0;
10         for(int i = 0; i < S.length(); ++i) {
11             int a = S.charAt(i) - 'A';
12             dp = dp + (i -last[a]) - (last[a] - secondLast[a]);
13             result += dp;
14             secondLast[a] = last[a];
15             last[a] = i;
16         }
17         
18         return result;
19     }
20 }

 Idea 2. Similar to Sum of Subsequence Widths LT891, instead of getting all the unique characters for substring ending at index i, focus on the contribution of each character, count how many times it appears as a unique character in a substring, then sum it up for each char in the string and get the result.

ABCBDAB, for the middle 'B', on the left, substring ending at 'B': B, CB

              on the right, substring starting at 'B': B, BD, BDA

'B' can appears 2 * 3 = 6 substring, B, BD, BDA, CB, CBD, CBDA,

It can observed that the count is depend on the nearest same char on the left and on the right,

  (i - prev) * (next - i)

Time complexity: O(n)

Space complexity: O(n)

Using hashmap to store the index of char in the string

 1 class Solution {
 2     public int uniqueLetterString(String S) {
 3         Map<Character, List<Integer>> charIndex = new HashMap<>();
 4         int n = S.length();
 5         for(int i = 0; i < n; ++i) {
 6             char c = S.charAt(i);
 7             if(!charIndex.containsKey(c)) {
 8                 charIndex.put(c, new ArrayList<Integer>());
 9             }
10             charIndex.get(c).add(i);
11         }
12         
13         long result = 0;
14         long mod = (long)1e9+7;
15         
16         for(List<Integer> positions: charIndex.values()) {
17             
18             for(int i = 0; i < positions.size(); ++i) {
19                 int prev = i > 0? positions.get(i-1) : -1;
20                 int next = i < positions.size()-1? positions.get(i+1) : n;
21                
22                 int curr = positions.get(i);
23                 result = (result + (curr-prev) * (next - curr))%mod; 
24             }
25         }
26         
27         return (int)result;
28     }
29 }

Idea 2.b store index at array prev[], next[] by scanning the string from left to right, and right to left

Time complexity: O(n)

Space complexity: O(n)

 1 class Solution {
 2     public int uniqueLetterString(String S) {
 3         int n = S.length();
 4         int[] charIndex = new int[26];
 5         Arrays.fill(charIndex, -1);
 6         
 7         int[] prev = new int[n];
 8         for(int i = 0; i < n; ++i) {
 9             int a = S.charAt(i) - 'A';
10             prev[i] = charIndex[a];
11             charIndex[a] = i;
12         }
13         
14         Arrays.fill(charIndex, n);
15         int[] next = new int[n];
16         for(int i = n-1; i >= 0;--i) {
17             int a = S.charAt(i) - 'A';
18             next[i] = charIndex[a];
19             charIndex[a] = i;
20         }
21     
22         int result = 0;
23         int mod = (int)(1e9) + 7;
24         
25         for(int i = 0; i < n; ++i) {
26             result = (result + (i - prev[i])*(next[i] - i))%mod;
27         }
28         
29         return result;
30     }
31 }

Example 1:

Input: "ABC"
Output: 10
Explanation: All possible substrings are: "A","B","C","AB","BC" and "ABC".
Evey substring is composed with only unique letters.
Sum of lengths of all substring is 1 + 1 + 1 + 2 + 2 + 3 = 10

Example 2:

Input: "ABA"
Output: 8
Explanation: The same as example 1, except uni("ABA") = 1.

猜你喜欢

转载自www.cnblogs.com/taste-it-own-it-love-it/p/10781583.html