【字符串】B049_LC_字符串的排列(滑窗)

一、Problem

Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. In other words, one of the first string’s permutations is the substring of the second string.

Input: s1 = "ab" s2 = "eidbaooo"
Output: True
Explanation: s2 contains one permutation of s1 ("ba").

二、Solution

方法一:滑窗

  • 窗口的含義
    • 囊括包含 s1 所有字符的子串
  • 窗口右移時機
    • 每次都右移
  • 窗口左移時機
    • 當前窗口找到了 s1 中的所有字符
  • 結算時機
    • 當前窗口找到了 s1 中的所有字符,並且窗口的大小 = s1 的長度,返回 true

這題的坑底點在於:問題並不是求解 s1 是否是 s2 的子串,求的是 s1 的某個排列是否是 s2 的子串,所以可以看看這個返回 true 的樣例:

"abcdxabcde"
"abcdeabcdx"
預期 true
class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int m = s1.length(), n = s2.length(), sig = 0, win[] = new int[258], need[] = new int[258];
        for (char c : s1.toCharArray()) {
            if (need[c] == 0)
                sig++;
            need[c]++;
        }
        char[] cs = s2.toCharArray();
        int match = 0, l = 0, r = 0;

        while (r < n) {
            if (++win[cs[r]] == need[cs[r]]) 
                match++;
            while (match == m) {
                if (r-l+1 == m)
                    return true;
                if (--win[cs[l]] < need[cs[l]]) 
                    match--;
                l++;
            }
            r++;
        }
        return false;
    }
}

修正後的邏輯:因爲不要求順序,所以當統計完一類字符到 match 中後,如果 match = sigle,就認爲排列找到。

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int m = s1.length(), n = s2.length(), sig = 0, win[] = new int[258], need[] = new int[258];
        for (char c : s1.toCharArray()) {
            if (need[c] == 0)
                sig++;
            need[c]++;
        }
        char[] cs = s2.toCharArray();
        int match = 0, l = 0, r = 0;

        while (r < n) {
            if (++win[cs[r]] == need[cs[r]]) 
                match++;
            while (match == sig) {
                if (r-l+1 == m)	 				
                	return true;
                if (--win[cs[l]] < need[cs[l]]) 
                	match--;
                l++;
            }
            r++;
        }
        return false;
    }
}

複雜度分析

  • 時間複雜度:O(n)O(n)
  • 空間複雜度:O(1)O(1)

比較套路的一種解法就是:利用 win[c] 來判別窗口內部的值

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int m = s1.length(), n = s2.length(), win[] = new int[258];
        for (char c : s1.toCharArray()) win[c]++;
        char[] cs = s2.toCharArray();
        int l = 0, r = 0;

        while (r < n) {
            char cr = cs[r++];
            win[cr]--;
            while (l < r && win[cr] < 0) {	//如果窗口內部有非s1字符
                win[cs[l]]++;
                l++;
            }
            if (r-l == m)
                return true;
        }
        return false;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章