遍歷小技巧:滑動窗口

問題

給定兩個字符串 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
    }
};
複製代碼
相關文章
相關標籤/搜索