1371 每个元音包含偶数次的最长字符串
给你一个字符串 s ,请你返回满足以下条件的最长子字符串的长度:每个元音字母,即 ‘a’,‘e’,‘i’,‘o’,‘u’ ,在子字符串中都恰好出现了偶数次。
示例1:
s = “eleetminicoworep”
输出: 13
思路:
1)遍历所有子字符串;超时
2)每一个字符串就是一个区间,区间状态可以用前缀和,用pre[i][k]
记录第i
个字符串之前第k
个元音的个数,[j,i]
字符串的某个元音的个数就是pre[i][k]-pre[j-1][k]
。判断每个元音是否符合,还是需要遍历两次。
3)奇偶性。题目中偶数次,所以我们不必在意出现多少次,只需要在意出现为奇数次或者偶数次,因为偶数-偶数=偶数,奇数-奇数=偶数。所以我们只需要记录每个元音的在第i
个字符的状态,0=偶数,1=奇数,键值对应多用Hash存储。键为元音字母,值为奇偶性。但是一旦键变多,不好维护。
可以采用bitmap来存储。二进制每一位正好对应奇偶性两种状态,因为有五位,最大为11111=2^5-1
,所以用一个32大小数组的数据存储对应状态的下标。
如 :s=“aba”;start = 00000;
s[0] = a = 00001,00000^00001 = 00001;a出现奇数次;
s[1] = b = 00010,00001^00010 = 00011;a,b出现奇数次;
s[2] = a = 00001,00011^00001 = 00010; a出现偶数次,b出现奇数次。
代码:
class Sulation{
int findTheLongestSubstring(string s){
//status状态
int ans = 0,status = 0,n = s.size();
//前置位未开始遍历数组为0
pos[0] = 0;
//遍历字符串,更新状态
for(int i = 0;i < n;++i){
if(s[i] == 'a') status ^= 1<<0;
else if(s[i] == 'e') status ^=1<<1;
else if(s[i] == 'i') status ^=1<<2;
else if(s[i] == 'o') status ^=1<<3;
else if(s[i] == 'u') status ^=1<<4;
//如果这种相同的状态出现,说明符合要求,计算子字符串长度,
if(pos[status]!=-1)
ans = max(ans,i+1-pos[status]);
//如果状态之前没出现过,计算位置坐标加1
else
pos[status] = i+1;
}
return ans;
}
}
PS:个人理解:针对pos[0] =0,和ans = max(ans,i+1-pos[status])\pos[status] = i+1;
如图:
位置 0 1 2 3 4 5
字符串 a b a b a
下标 0 1 2 3 4
数组pos[]记录的是元音字母第一次出现的位置,pos[0] = 0没有开始遍历。i+1使得下标对应上位置
Python:
下标即位置,规定dp[0]=1;
def findTheLongestString(self,s:str)->int:
dp = [-float('inf')]*32
dp[0] = -1
pattern = 0
ans = 0
for i in rang(len(s)):
if s[i] =='a':
pattern^=(1<<0)
elif s[i] == 'e':
pattern^=(1<<1)
elif s[i] == 'i':
pattern^=(1<<2)
elif s[i] == 'o':
pattern^=(1<<3)
elif s[i] == 'u':
pattern^=(1<<4)
if dp[pattern] != -float('inf'):
cur_len = i-dp[pattern]
res = max(cur_len,res)
else:
dp[pattern] = i
return res