利用二进制进行状态压缩

利用二进制进行状态压缩

当我们遍历数据结构时,需要对某个状态进行保存时,我们一般用字典或者数组来记录,这样做其实比较浪费空间。如遍历字符串时记录元音 ( a 、 e 、 i 、 o 、 u ) (a、e、i、o、u) aeiou出现次数的奇偶性,一般用unordered_map<char,int>times,每出现一次元音x,time[x]++,遍历完后判断time[x]的奇偶性。很费空间。

其实我们可以发现,奇偶性实际上只有两种结果,0 o r or or 1,0为偶,1为奇。不妨我们用5位二进制 00000 00000 00000 来表示 ( a 、 e 、 i 、 o 、 u ) (a、e、i、o、u) aeiou的奇偶性,那么一共2^5=32种状态,由于大部分语言不直接提供二进制数据类型,我们不妨用整型state来代替二进制,那么state的取值范围是0~31。

如果用 S ( i , j ) S(i,j) S(i,j)表示 i 到 j i到j ij的状态(元音出现次数的奇偶性,一共32种),若 S ( 0 , i ) = S ( 0 , j ) S(0,i)=S(0,j) S(0,i)=S(0,j),那么 S ( i + 1 , j ) S(i+1,j) S(i+1,j)必定为0 。
为什么?因为状态相同说明5个bit个个相同,因为每出现一个元音bit都要改变一次(取一次异或),bit没变就说明bit取了偶数次异或
利用这个原理,我们就可以找到每个元音都出现偶数次的最长子串:

class Solution {
public:
//我们就可以从前往后遍历,记录每种状态第一次出现和最后一次出现的位置,位置差就是该状态的下的最长子串长,遍历所有状态即可得到答案
    int findTheLongestSubstring(string s) {
        int n=s.size();
        int state=0;
        vector<vector<int>> indexs(32,vector<int>(2,-2));//记录每种状态第一次和最后一次的位置
        indexs[0][0]=-1; //空串时,状态为0

        for(int i=0;i<n;i++){
            switch(s[i]){
                case 'a':state^=16;break;
                case 'e':state^=8;break;
                case 'i':state^=4;break;
                case 'o':state^=2;break;
                case 'u':state^=1;break;
            }
            if(indexs[state][0]==-2)//第一次出现
            indexs[state][0]=i;

            indexs[state][1]=i;//最后一次出现
        }

        int start=0,end=-1;
        for(int i=0;i<32;i++)
        if((end-start)<(indexs[i][1]-indexs[i][0])){
            start=indexs[i][0]+1;//S(0,i)=S(0,j),那么S(i+1,j)必定为0 。
            end=indexs[i][1];
        }
        return end-start+1;
    }
};

总结:若需要记录若干个变量的状态,且这些变量的状态只有0 o r or or 1,那么可以考虑用二进制数来代替数组和字典,状态发生变化时用1进行异或

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NLP饶了我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值