其他分享
首页 > 其他分享> > LeetCode 5799 最美字符串的数目

LeetCode 5799 最美字符串的数目

作者:互联网

题目:https://leetcode-cn.com/problems/number-of-wonderful-substrings/

前缀和pre[i]定义为:s[0…i]中各个字母出现的奇偶性;
pre[i] = pre[i - 1] ^ (1 << (s[i] - ‘a’));
前缀和之差 pre[j] - pre[i - 1]表示:子串s[i…j] 中每个字母出现次数的奇偶性;(本题中用异或运算表示)
(1 << (s[i] - ‘a’)) 表示新增字符的二进制位为1,其他位为0;
该异或运算可以只改变单个二进制位的奇偶性。
如果下标不同位置的前缀和相等,则说明 前缀和i-1 以及 前缀和j 中各个字母出现的奇偶性是一样的。 
即 pre[i - 1] = pre[j],
则子串 s[i…j] 中每种字母都出现偶数次。 
(intuition: 偶数 - 偶数 = 偶数, 奇数 - 奇数 = 奇数)
所以如果前缀子串s[0…j]中某个字母出现的奇偶性和前缀子串s[0…i-1]中该字母出现的奇偶性一样,则该字母在子串s[i…j]中一定出现偶数次。
  1. 对于当前前缀和,找到与之相等的前缀和个数cnt1;
  2. 对于当前前缀和,枚举每个二进制位并将该二进制位取反(假设该二进制位表示的字母出现奇数次),找到与某个二进制位取反后的前缀和相等的前缀和个数cnt2;
1.
pre[i] = pre[i - 1] ^ (1 << (s[i - 1] - ‘a’));
ans += cnt[pre[i]];
 
2.
for(int i = 1; i < 1024; i <<= 1) {
    ans += cnt[pre[i] ^ i];
}

 

代码:
 1 class Solution {
 2 public:
 3     long long wonderfulSubstrings(string word) {
 4         vector<long> cnt(1025, 0);
 5         cnt[0] = 1; // 空字符串
 6         int pre = 0;
 7         long ans = 0;
 8         for(char ch : word) {
 9             pre ^= (1 << (ch - 'a'));
10             ans += cnt[pre];
11             for(int i = 1; i < 1024; i <<= 1) {
12                 ans += cnt[pre ^ i];
13             }
14             cnt[pre]++;
15         }
16         return ans;
17     }
18 };

 

标签:pre,前缀,二进制位,字母,最美,奇偶性,偶数,LeetCode,5799
来源: https://www.cnblogs.com/tristatl/p/14941199.html