遍历小技巧:滑动窗口

问题

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

示例:java

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

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

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

解法1:

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

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

解法2:

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

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

具体解法以下:code

/** * @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
    }
};
复制代码
相关文章
相关标签/搜索