遍历小技巧:滑动窗口

问题

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

示例:

输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").

输入: s1= "ab" s2 = "eidboaoo"
输出: False
复制代码

输入的字符串只包含小写字母,两个字符串的长度都在 [1, 10,000] 之间。

解法1:

遍历整个 s2,每次取固定长度的字符串,然后和 s1 进行比较.

这种解法的时间复杂度为 N 的三次方。leetcode上会提示超时。。显然不太可行

解法2:

事先准备一个字典和初始的窗口,字典和窗口里都保存了对应字母出现的次数。然后开始遍历 s2,每次都比较一下字典和窗口里的字母对应出现次数一致不一致,如果不一致则将窗口第一个字母数量-1,将窗口下一个字母加进去。 这样相当于每一次遍历都向右平移了一下窗口,而且可以保留之前的大部分数据。

这种解法的时间复杂度为 N 的二次方。测试通过,开心。

具体解法如下:

/**
 * @param {string} s1
 * @param {string} s2
 * @return {boolean}
 */
var checkInclusion = function(s1, s2) {
    if(s1.length > s2.length){
        return false
    }
    
    if(s1.length === 1){
        return s2.includes(s1)
    }
    
    let book={},myBook={}
    
    // 创建字典
    for(let i=0;i<s1.length;i++){
        book[s1.charAt(i)] ? book[s1.charAt(i)]++ : book[s1.charAt(i)] = 1
    }
    
    // 保存第一个窗口
    for(let i=0;i<s1.length;i++){
        myBook[s2.charAt(i)] ? myBook[s2.charAt(i)]++ : myBook[s2.charAt(i)] = 1
    }
    
    // 开始滑动窗口
    for(let i=s1.length;i<=s2.length;i++){
        if(check(book,myBook)){
            return true
        }else{
            myBook[s2.charAt(i-s1.length)]--
            myBook[s2.charAt(i)] ? myBook[s2.charAt(i)]++ : myBook[s2.charAt(i)] = 1
        }
    }
    
    return false
    
    // 比较字典和窗口
    function check(book,myBook){
        let keys = Object.keys(book)
        for(let i=0;i<keys.length;i++){
            if(book[keys[i]] !== myBook[keys[i]]){
                return false
            }
        }
        return true
    }
};
复制代码

猜你喜欢

转载自blog.csdn.net/weixin_34034261/article/details/91379178