一、题目
1、题目描述
给你一个字符串
s
。请返回s
中最长的 超赞子字符串 的长度。「超赞子字符串」需满足满足下述两个条件:
- 该字符串是
s
的一个非空子字符串- 进行任意次数的字符交换后,该字符串可以变成一个回文字符串
2、接口描述
python3
class Solution:
def longestAwesome(self, s: str) -> int:
cpp
class Solution {
public:
int longestAwesome(string s) {
}
};
3、原题链接
二、解题报告
1、思路分析
这道题应该说一下子字符串是连续的。。。
我们考虑回文串的特点:至多有一个字符出现次数为奇数
那么对于超赞子串S[i,j]而言,一定满足最多只有一个字符出现次数为奇数
我们可以用10位二进制数字分别表示前缀[0, i]内字符0~9出现次数奇偶性
那么我们可以通过前缀和快速判断S[i,j]是否是超赞子串
而我们要的是最长长度
我们用prexor[i]代表到下标i为止字符出现次数奇偶性的前缀状态
我们发现如果S[i, j]满足每个字符都是偶次出现,那么prexor[i - 1] ^ prexor[j] = 0 => prexor[i - 1] = prexor[j]
如果S[i, j] 只有一个字符出现次数为奇数,那么prexor[i - 1] ^ prexor[j] 的 1 的个数为1
所以我们用哈希表pre统计每个前缀状态的最早出现下标,然后边遍历边维护前缀状态msk
对于每个msk,偶数超赞子串我们其最大长度为i - pre[msk]
奇数超赞子串,其最大长度为 i - pre[msk ^ (1 << k)]
pre哈希表初始都为n,然后pre[0] = -1
2、复杂度
时间复杂度: O(nU),U为字符个数 空间复杂度:O(1 << U)
3、代码详解
python3
class Solution:
def longestAwesome(self, s: str) -> int:
n = len(s)
pre = [n] * (1 << 10)
msk = ret = 0
pre[0] = -1
for i, x in enumerate(map(int, s)):
msk ^= (1 << x)
ret = max(ret, i - pre[msk], max(i - pre[msk ^ (1 << b)] for b in range(10)))
if pre[msk] == n:
pre[msk] = i
return ret
cpp
class Solution {
public:
int longestAwesome(string s) {
int n = s.size(), msk = 0, ret = 0;
vector<int> pre(1 << 10, n);
pre[0] = -1;
for (int i = 0; i < n; i ++) {
msk ^= 1 << (s[i] ^ 48);
ret = max(ret, i - pre[msk]);
for (int j = 0; j < 10; j ++) ret = max(ret, i - pre[msk ^ 1 << j]);
if (pre[msk] == n) pre[msk] = i;
}
return ret;
}
};