• 1371.每个元音包含偶数次的最长子字符串


    image-20200521155625739

    前缀和+状态压缩

    代码

    /*
     * 1. 记录a e i o u构成整体的状态  范围在00000~11111
     * 2. 如果两次出现了相同的状态,
     *    假设第一次出现在i处,第二次出现的j处,
     *    那么 i+1 ~ j 之间的字符串肯定是满足aeiou出现均为偶数次数的。
     * 3. 因为只有经历了偶数个aeiou,才能回到之前的状态。
     * 4. 为了使得合理的字符串长度最长,需在第一次出现此状态时,就需要记录到下标,然后下一次碰到相同的状态,就  		计算最大长度。
     *
     *14ms
     *时间复杂度 O(n)
     */
    class Solution {
        public int findTheLongestSubstring(String s) {
            int n=s.length();
            int[] pos=new int[32];
            Arrays.fill(pos, Integer.MAX_VALUE);
            int ans=0,status=0;
            pos[0]=-1;
            for(int i=0;i<n;i++){
                //更新子串的状态  u o i e a
                char ch=s.charAt(i);
                if(ch=='a'){
                    status^=(1);
                }else if(ch=='e'){
                    status^=(1<<1);
                }else if(ch=='i'){
                    status^=(1<<2);
                }else if(ch=='o'){
                    status^=(1<<3);
                }else if(ch=='u'){
                    status^=(1<<4);
                }
    
                if(pos[status]==Integer.MAX_VALUE){
                    pos[status]=i;
                }else{
                    ans=Math.max(ans, i-pos[status]);
                }
            }
            return ans;
        }
    }
    
    

    思路

    • 将5个元音字母整体出现的奇偶性 视为一个状态,共2^5即32种状态。
    • 如果子串[0,i]与子串[0,j]状态相同,那么子串[i+1,j]的状态一定是00000,理由如下:
      • 假设第一次出现在 i 处,第二次出现的j处,那么 i+1 ~ j 之间的字符串肯定是满足aeiou出现均为偶数次数的。因为只有经历了偶数个aeiou,才能回到之前的状态。
        • 两个数奇偶性相同,相减一定是偶数
        • 两个数奇偶性不同,相减一定时奇数
    • [i+1,j]的长度是 j-(i+1) +1=j-i;即j-i就是符合要求的长度。
    • 为了使得合理的字符串长度最长,只需要记录第一次出现该状态的下标即可。
    • 需要注意状态0首次出现的位置应该设定为-1 原因:
      • 初始化是status已经设置为0,默认已经出现过。
      • pos[0]不设置为-1,下标都是从0开始的,假设第一个字母为 'l' ,与status异或后,status=0符合要求(子串中各元音字符出现次数为0也成立),长度应为1。按照i-pos[status] 公式计算,则计算结果为i+Integer.MAX_VALUE,显然有误。所以pos[0]设置为-1

    官方代码

    /*
     *14ms
     *时间复杂度 O(n)
     */
    class Solution {
        public int findTheLongestSubstring(String s) {
            int n = s.length();
            int[] pos = new int[1 << 5];
            Arrays.fill(pos, -1);
            int ans = 0, status = 0;
            pos[0] = 0;
            for (int i = 0; i < n; i++) {
                char ch = s.charAt(i);
                if (ch == 'a') {
                    status ^= (1 << 0);
                } else if (ch == 'e') {
                    status ^= (1 << 1);
                } else if (ch == 'i') {
                    status ^= (1 << 2);
                } else if (ch == 'o') {
                    status ^= (1 << 3);
                } else if (ch == 'u') {
                    status ^= (1 << 4);
                }
                if (pos[status] >= 0) {
                    ans = Math.max(ans, i + 1 - pos[status]);
                } else {
                    pos[status] = i + 1;
                }
            }
            return ans;
        }
    }
    
    
    • 官方代码中,p[0]=0?计算长度i+1-pos[status] 和 pos[status]=i+1不是特别理解

    参考链接:

    江户川柯基:简单的思路

    官方题解

  • 相关阅读:
    解决:只有 DBA 才能导入由其他 DBA 导出的文件
    查找—顺序查找
    软件测试,想说爱你不容易
    Oracle常用SQL
    排序—直接插入排序
    排序—归并排序
    排序—快速排序
    排序—选择排序
    查找—折半查找
    排序—堆排序
  • 原文地址:https://www.cnblogs.com/yh-simon/p/12931706.html
Copyright © 2020-2023  润新知