Leetcode5337.每个元音包含偶数次的最长子字符串——状态压缩DP

文章目录

引入

在本周的双周赛中,出现了这么一道题

给你一个字符串 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 次。

一开始我想的是回溯法,也就是在每个字符上选或者不选,但是很明显会又重复计算,需要用一个数组来剪枝。

俗话说得好,能用回溯法的题一定能用动态规划算法。
所以这道题有一个思路清奇的解法,使用状态压缩DP。其实状态压缩DP在我们之前的N皇后问题中也谈到过,当时的用法就足以让人震惊了:使用位运算的左右移动来判断左右是否有人坐。

这里则是用位运算的异或来表示每个元音字母的奇偶出现的次数。

题解

将5个元音字母出现次数的奇偶视为一种状态,一共有 2 5 2^5 25=32种状态。所以不妨使用一个二进制位数为5位的整数代表状态,第0位为1表示a出现奇数次,第一位为1表示e出现奇数次……以此类推。

所以使用异或判断,如果a出现第一次,0^1=1,如果a出现第二次1^1=0。同理,如果e第一次出现是00^10=10,第二次出现则是10^10=00
由此所以我们知道,要想满足题目要求出现的次数都是偶数,那么只有二进制00000才满足要求。

所以现在的问题是,怎么去找这个00000。我们知道,如果子串[0,i]与字串[0,j]状态相同,那么字串[i+1,j]的状态一定是0。

另外需要注意状态0首次出现的位置应该设定为-1。

直接上代码理解:

class Solution {
    public int findTheLongestSubstring(String s) {
        int[] pre=new int[32];
        Arrays.fill(pre,Integer.MAX_VALUE);
        pre[0]=-1;
        int length=s.length();
        int curr=0;
        int ans=0;
        for(int i=0;i<length;i++){
            switch(s.charAt(i)){
                case 'a':curr^=1;break;
                case 'e':curr^=2;break;
                case 'i':curr^=4;break;
                case 'o':curr^=8;break;
                case 'u':curr^=16;break;
                default:break;
            }
            if(pre[curr]==Integer.MAX_VALUE) {
                pre[curr]=i;
            }else {
                ans=Math.max(ans,i-pre[curr]);
            }
        }
        return ans;
    }
}

我们看到关键的其实就是if…else…上的判断。
这个if判断下的pre[curr]=i;有两层含义,第一层是如果判断成立记录下当前状态的位置i,第二层是只记录第一次出现这个状态的位置i,因为我们需要的是最长子字符串。
else下的语句就是记录两次相同状态的情况下的字符串长度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值