秋招每日一题T30——每个元音包含偶数次的最长子字符串

题目描述

给你一个字符串 s ,请你返回满足以下条件的最长子字符串的长度:每个元音字母,即 ‘a’,‘e’,‘i’,‘o’,‘u’ ,在子字符串中都恰好出现了偶数次。
在这里插入图片描述
在这里插入图片描述

思路

①由于问题的规模在5×105,因此需要使用O(n)的算法,否则在leetcode上会TLE。
②使用的算法是状态压缩,由于本题所判断的最长子列,需要五个元音字母出现偶数次,偶数次有以下性质:

  • 0次也算偶数次,因此如果一个字符串从未出现过元音字母,那么它自身便是最长的子串。
  • 当前状态下,如果某个元音字母再次出现偶数次,那么它的状态是不变的,因为偶数 + 偶数还是偶数。只有当遇到奇数次时,状态才会改变。
  • 因此可以使用一个位图来记录某个状态上一次出现在哪个位置,一共有32个状态,即位图的00000~11111
  • 从头到尾线性遍历字符串,如果出现元音字母,寻找上一次(或者说,第一次出现的位置)它出现的位置。
  • 直到下一次状态改变之前,前面的子串如果满足条件,那么就是最长的子串。出现偶数次不会改变状态,但是出现奇数次则会出现新的状态。出现新的状态时记录新的状态,否则更新原状态。

代码

class Solution {
public:
    int findTheLongestSubstring(string s) {
        vector<int> count(32,-2);
        count[0] = -1;  //0个状态:所有元音字母均出现0次,此时i - count[0]即为字符串长度。
        int state = 0,res = 0;
        string cs = "aeiou";
        for(int i=0;i<s.size();i++){
            int k = cs.find(s[i]);
            if(k != -1){//找不到值,返回-1.
                state ^= 1 << k;
            }
            if(count[state] != -2)  res = max(res, i-count[state]);
            else                    count[state] = i;
        }
        return res;
    }
};

版权声明:本文为fatfairyyy原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。