题目
给你一个字符串 s 。请返回 s 中最长的 超赞子字符串 的长度。
「超赞子字符串」需满足满足下述两个条件:
- 该字符串是 s 的一个非空子字符串
- 进行任意次数的字符交换后,该字符串可以变成一个回文字符串
实例1:
输入:s = "3242415"
输出:5
解释:"24241" 是最长的超赞子字符串,交换其中的字符后,可以得到回文 "24142"
实例2:
输入:s = "12345678"
输出:1
实例3:
输入:s = "213123"
输出:6
解释:"213123" 是最长的超赞子字符串,交换其中的字符后,可以得到回文 "231132"
实例4:
输入:s = "00"
输出:2
思路
这道题看题解也断断续续理解了好几天,状态压缩都忘得差不多了
步骤:
- 形成超赞字符串只有2种情况:①所有数字的个数都是偶数 ②只有一个数字的个数是奇数
- 用二进制位运算进行状态压缩,从右往左表示每个数字的数量的奇偶情况(为1表示数字的数量为奇数,为0表示数字的数量为偶数,例如两个1的时候,1^1=0,因此用0表示偶数,1表示奇数。)
- 用dp数组记录下每个二进制压缩状态最先出现的位置,后面如果再出现该状态,表示这是一个回文串(因为所有的数字又重复出现了一遍才会导致后面的状态和前面的状态相同),长度为i-dp[str](对应①所有数字的个数都是偶数)
- 尝试改变一个数字(0-9)的数量,查看改变后的状态是否存在,若存在,表示这也是一个回文串(对应 ②只有一个数字的个数是奇数)
代码
class Solution {
public:
int longestAwesome(string s) {
int ans = 0, str = 0, n = s.size(); //str记录状态
vector<int> dp(1<<10, INT_MAX);
dp[str] = -1; //状态为0证明所有数字都出现了偶数遍
for(int i=0; i<n; i++){
str ^= (1<<(s[i]-'0'));
//只有一个数字不同(奇数)
for(int j=0; j<10; j++){
int tmp = str^(1<<j);
ans = max(ans, i-dp[tmp]);
}
//偶数
//若该状态未出现过,记录最开始的位置
if(dp[str]==INT_MAX)
dp[str] = i;
else //该状态出现过了,则计算i-dp[str]未回文串长度
ans = max(ans, i-dp[str]);
}
return ans;
}
};