LeetCode 1371 每个元音包含偶数次的最长子字符串 做题感悟

Posted swsbty

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 1371 每个元音包含偶数次的最长子字符串 做题感悟相关的知识,希望对你有一定的参考价值。

题目链接:

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

 

一开始不会做,看了题解并和朋友讨论过后,终于弄懂官方解答为什么那么写了!

 

先贴一下官方解答的代码:

 1 class Solution {
 2     public int findTheLongestSubstring(String s) {
 3         int n = s.length();
 4         int[] pos = new int[1 << 5];
 5         Arrays.fill(pos, -1);
 6         int ans = 0, status = 0;
 7         pos[0] = 0;
 8         for (int i = 0; i < n; i++) {
 9             char ch = s.charAt(i);
10             if (ch == ‘a‘) {
11                 status ^= (1 << 0);
12             } else if (ch == ‘e‘) {
13                 status ^= (1 << 1);
14             } else if (ch == ‘i‘) {
15                 status ^= (1 << 2);
16             } else if (ch == ‘o‘) {
17                 status ^= (1 << 3);
18             } else if (ch == ‘u‘) {
19                 status ^= (1 << 4);
20             }
21             if (pos[status] >= 0) {
22                 ans = Math.max(ans, i + 1 - pos[status]);
23             } else {
24                 pos[status] = i + 1;
25             }
26         }
27         return ans;
28     }
29 }
30 
31 作者:LeetCode-Solution
32 链接:https://leetcode-cn.com/problems/find-the-longest-substring-containing-vowels-in-even-counts/solution/mei-ge-yuan-yin-bao-han-ou-shu-ci-de-zui-chang-z-2/
33 来源:力扣(LeetCode)
34 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

既然是看了别人的正确答案,通过理解才弄懂的,那我就来讲解一下官方解答的这段代码吧!

1.下面这段代码的意思是定义一个数组,数组的大小为32,用来保存 “aeiou“奇偶情况(32种)出现时在字符串中的位置。

(注:1 << 5 表示 1的二进制形式往左移5位,即(100000) = (32)16)

int[] pos = new int[1 << 5];

 

2.这段代码表示向pos数组中每一个元素的值置为 -1(一开始,还没有对字符串检索前,aeiou奇偶的各种情况都没有出现过,都记为 -1)。

Arrays.fill(pos, -1);

 

3.在这段代码中,ans表示最终要return的偶数次元音最长子字符串的长度;

status 用来表示 aeiou奇偶次数二进制的十进制形式(XXXXX,从右到左分别表示 a e i o u 出现的次数是奇数还是偶数,0表示偶,1表示奇)。

例如:status 的值为 2 时,二进制形式为 00010,表示 e 是奇次,其余都是偶次。

int ans = 0, status = 0;

 

4.将数组的第0位赋值为0,是因为第0位表示 全偶 (即 00000),在还没有开始检索字符串之前,因为还没开始检索,还没开始,当然都为0,出现了全偶次的aeiou,出现的位置为0。

pos[0] = 0;

 

5.将字符串从第一位字符开始检索是否是元音,如果是元音就将 二进制形式的 status (status的二进制形式为 XXXXX,从右到左分别表示 a e i o u 出现的次数是奇数还是偶数,0表示偶,1表示奇)中对应元音位置的数异或,

即如果之前是0,那么异或之后就是1,反之,如果之前是1,那么异或之后就是0。”判断“在下面讨论。

 1         for (int i = 0;i < s.length();i++) {
 2             char ch = s.charAt(i);
 3             if (ch == ‘a‘) {
 4                 status ^= 1;
 5             } else if (ch == ‘e‘) {
 6                 status ^= (1 << 1);
 7             } else if (ch == ‘i‘) {
 8                 status ^= (1 << 2);
 9             } else if (ch == ‘o‘) {
10                 status ^= (1 << 3);
11             } else if (ch == ‘u‘) {
12                 status ^= (1 << 4);
13             }
14 
15             if (pos[status] >= 0) {
16                 ans = Math.max(ans, i + 1 - pos[status]);
17             } else {
18                 pos[status] = i + 1;
19             }
20         }

 

6.如果 pos[status] >= 0 表示 如果这种奇偶情况以前出现过,就将 当前的位置的长度和之前的位置的长度相减(去掉前缀),让其变为全偶,和 之前的全偶比较长度,留下更长的那个长度作为返回值ans。

否则,如果 pos[status] < 0,即 pos[status] = -1 (-1为之前的预设值),表示 这种 奇偶情况 以前没有出现过,此时的status不是全偶,就将现在的长度记录到这种情况中。(下次再遇到就可以把它减去了)

1             if (pos[status] >= 0) {
2                 ans = Math.max(ans, i + 1 - pos[status]);
3             } else {
4                 pos[status] = i + 1;
5             }

 

7.最后把ans(最长全偶)作为返回值返回。

 

总结:

核心就是 每次遍历时,检查xxxxx的情况是否出现过,如果没出现过就记录这个出现的位置,如果出现过就减去前一次的位置(把前面那次的长度剪掉)。

以上是关于LeetCode 1371 每个元音包含偶数次的最长子字符串 做题感悟的主要内容,如果未能解决你的问题,请参考以下文章

[LeetCode]Single Number 异或的妙用

[LeetCode]319. Bulb Switcher灯泡开关

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现偶数次。找出那个只出现了一次的元素。

LeetCode-1220 统计元音字母序列的数目

一个布尔递归函数,用于判断一个数字是不是在整数中出现偶数次

《程序员代码面试指南》第七章 位运算 在其他数都出现偶数次的数组中找到出现奇数次的数