107.字符串的排列

一、题目描述

给你两个字符串 s1s2 ,写一个函数来判断 s2 是否包含 s1 的排列。换句话说,s1 的排列之一是 s2子串
在这里插入图片描述

二、解题思路

使用滑动窗口,以s1="ab",s2="aidbaooo"为例,模拟一下滑动窗口的过程。
在这里插入图片描述
首先需要计数,获得s1中每个字符出现的次数,然后遍历s2,每出现一个s1中的字符,就将计数减1,当s1中所有的字符都出现了,并且窗口长度等于s1的长度时,说明在s2中找到了s1的排列。下面是s1中的字符计数
在这里插入图片描述
第一步:遍历s2,第一个字符是a,就与s1中的抵消掉,该字符计数减1,a—>0;
在这里插入图片描述

第二步:当遍历到第二个字符i时,发现它不是s1中的字符,将其计数为-1,
在这里插入图片描述
在这里插入图片描述

第三步:当当前窗口出现不属于s1中的字符的时候,此时要缩短窗口,left移动到i的后面一位,这时我们要重新计数了,因为在新的窗口里每个字符有没有出现还不知道,要恢复原样,新窗口的起始如下,d出现了,但不属于s1,所以计数为-1:
在这里插入图片描述
在这里插入图片描述
第四步:同第三步一样,当当前窗口出现不属于s1中的字符的时候或者遇到计数为-1时,这是更新窗口,从新的起点开始,计数更新,下一个元素是b,在s1中有,则其计数减一,同时其它元素计数根据当前窗口中是否出现更新:
在这里插入图片描述
第五步:right继续后移,a出现在s1中,此时整好ab计数都为0了,并且窗口长度也是s1的长度,此时返回true即可。
在这里插入图片描述
在这里插入图片描述

三、代码演示

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int n = s1.length(), m = s2.length();
        if (n>m){
            return false;
        }
        //先统计字符串s1中每个字符出现的次数
        int[] cnt = new int[26];
        for (int i=0; i<n; i++){
            cnt[s1.charAt(i)-'a']++;
        }

        //声明两个指针
        int left=0, right=0;
        while (right<m){
            //拿到s2中当前字符对应在26个字母中的索引
            int x = s2.charAt(right)-'a';
            cnt[x]--;
            while (cnt[x]<0){
                //通过缩减窗口使得cnt[x]不为负数,相当于第三步
                cnt[s2.charAt(left)-'a']++;
                left++;
            }
            //当前窗口长度等于s1的长度且s1中字符的计数都是0
            if (right-left+1==n){
                return true;
            }
            right++;
        }
        return false;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值