[LeetCode] 1371. Find the Longest Substring Containing Vowels in Even Counts 每个元音包含偶数次的最长子字符串


Given the string s, return the size of the longest substring containing each vowel an even number of times. That is, 'a', 'e', 'i', 'o', and 'u' must appear an even number of times.

Example 1:

Input: s = "eleetminicoworoep"
Output: 13
Explanation: The longest substring is "leetminicowor" which contains two each of the vowels: e, i and o and zero of the vowels: a and u.

Example 2:

Input: s = "leetcodeisgreat"
Output: 5
Explanation: The longest substring is "leetc" which contains two e's.

Example 3:

Input: s = "bcbcbc"
Output: 6
Explanation: In this case, the given string "bcbcbc" is the longest because all vowels: a, e, i, o and u appear zero times.

Constraints:

  • 1 <= s.length <= 5 x 10^5
  • s contains only lowercase English letters.

这道题说是给了个字符串s,让找出一个最长子串,使得其中的元音字母出现次数为偶数次。这里的元音字母就是那五个 a,e,i,o,u。这道题的难点还是在于如何统计元音字母的个数,并且判断他们是否都为偶数,大多数人可能第一时间就会考虑用个 HashMap 来统计元音字母出现的个数,然后再分别判断是不是偶数个。其实这里我们对具体的个数并不关心,只要知道是不是偶数,实际上每个元音只有奇数和偶数两种状态,总共五个元音,则共有 2^5 = 32 种状态,那么正好可以使用位运算的思想来记录状态,五个元音各用一个二进制的位来记录状态,0即为偶数,1为奇数,这里a在最低位,其次按顺序是 e,i,o,u。则二进制 00000 就表示五个元音全是偶数,00011 就表示元音a和e为奇数,这里每一位对应的十进制数分别为1,2,4,8,16。这样范围为 [0, i] 内的子串的元音奇偶数状态就知道了,同时还要记录下第一个出现非0状态的位置,当下次再次出现相同的状态码时,比如 [0, j] 范围内的子串也是相同的状态,则范围 [i, j] 内的子串必定元音都是偶数个的,这样可以快速来更新结果 res。

明白了这点后,可以来写代码了,这里的状态码用一个整型数 mask 来表示,同时为了更方便的取出每个元音位对应的十进制数,可以用一个 HashMap 来建立映射。然后还需要一个状态值和下标之间的映射,这里可以用 HashMap,或者一个大小为 32 的数组 mask2idx 就行,因为状态码是不会超过32的整型数,初始化值为 -1。然后可以开始遍历了,将遍历到的字母到 vowelMap 中取值,如果是元音,就会取到对应的非零值,然后 mask 异或上这个值,此时若 mask 不为0,且当前的 mask 值之前并没有出现过,即在 mask2idx 中的值是 -1,此时就更新其值为i。然后用 i - mask2idx[mask] 来更新结果 res 即可,参见代码如下:


class Solution {
public:
    int findTheLongestSubstring(string s) {
        int res = 0, mask = 0, n = s.size();
        unordered_map<char, int> vowelMap{{'a', 1}, {'e', 2}, {'i', 4}, {'o', 8}, {'u', 16}};
        vector<int> mask2idx(32, -1);
        for (int i = 0; i < s.size(); ++i) {
            mask ^= vowelMap[s[i]];
            if (mask != 0 && mask2idx[mask] == -1) {
                mask2idx[mask] = i;
            }
            res = max(res, i - mask2idx[mask]);
        }
        return res;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1371


参考资料:

https://leetcode.com/problems/find-the-longest-substring-containing-vowels-in-even-counts/description/

https://leetcode.com/problems/find-the-longest-substring-containing-vowels-in-even-counts/editorial/

https://leetcode.com/problems/find-the-longest-substring-containing-vowels-in-even-counts/solutions/534135/c-java-with-picture/


LeetCode All in One 题目讲解汇总(持续更新中...)

posted @ 2025-05-27 21:07  Grandyang  阅读(36)  评论(0)    收藏  举报
Fork me on GitHub