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

题目来源:题目

题目

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

 

示例 1:

 

输入:s = "eleetminicoworoep"

输出:13

解释:最长子字符串是 "leetminicowor" ,它包含 e,i,o 各 2 个,以及 0 个 a,u 。

示例 2:

 

输入:s = "leetcodeisgreat"

输出:5

解释:最长子字符串是 "leetc" ,其中包含 2 个 e 。

示例 3:

 

输入:s = "bcbcbc"

输出:6

解释:这个示例中,字符串 "bcbcbc" 本身就是最长的,因为所有的元音 a,e,i,o,u 都出现了 0 次。

 

 

提示:

 

1 <= s.length <= 5 x 10^5

s 只包含小写英文字母。

思路

思路一暴力算法

       找到所有的字串,判断该字串中的所有元音字母的个数是否为偶数,如果满足都是偶数的条件,则更新字串最大长度。

       其中,找到所有字串的时间复杂度为O(n^2),在字串中找元音字母个数的时间复杂度为O(n),所以总的时间复杂度为O(n^3).会超过时间限制。

思路二前缀和

       考虑给定一个字串,如何更快的判断该字串中元音字母的个数。假设给定字串为[i,j],表示原字符串的第i个字母到第j个字母。可以用前缀和的方式记录从0-i和0-j个字符中每个元音的个数pre[i][k],pre[j][k],则字串[i,j]中元音个数为pre[j][k] – pre[i-1][k]。k表示五个元音字符的第k个。

       由于我们只要判断该字串中元音字母的个数的奇偶,所以我们可以用前缀和记录元音个数的奇偶。由于奇数减去奇数和偶数减去偶数都为偶数,所有只要pre[j][k]和pre[i-1][k]的奇偶性相同即可。

       现在考虑如何找字串?不用遍历所有的字串,而是考虑直接求出以下标j结尾的最大字串长度,就可以先找到与第j个字母的奇偶性相同的字符下标i,然后用j-i+1就是以j结尾的字串最大长度。所以我们可以记录每种奇偶性第一次出现的位置。

       因为有5个元音字母,所以奇偶性一共有32中,可以用5位记录奇偶性,0表示该字母出现偶次,1表示该字母出现奇数次。

 

代码

public static int findTheLongestSubstring(String s) {

        int[] pos = new int[32];

        int ans = 0, status = 0;

        Arrays.fill(pos, -1);

        pos[0] = 0;

        for (int i = 0; i < s.length(); i++) {

            char c = s.charAt(i);

            if (c == 'a') {

                status ^= (1 << 0);

            } else if (c == 'o') {

                status ^= (1 << 1);

            } else if (c == 'e'){

                status ^= (1 << 2);

            } else if (c == 'i') {

                status ^= (1 << 3);

            } else if (c == 'u') {

                status ^= (1 << 4);

            }

            if (pos[status] >= 0) {

                ans = Math.max(ans, i + 1 - pos[status]);

            } else {

                pos[status] = i + 1;

            }

        }

        return ans;

    }

总结

思路二的时间复杂度为O(n).

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值