一、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;
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,
比較套路的一種解法就是:利用 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;
}
}