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) 2 = (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]319. Bulb Switcher灯泡开关