🧠
Sliding Window with Match Count Optimization
💡 This approach further optimizes by avoiding full frequency array comparisons on every step, instead tracking how many characters currently match the required frequency.
Intuition
Maintain a count of how many characters have the exact required frequency in the current window. When this count equals the number of unique characters in s1, we have a valid permutation.
Algorithm
- Count frequency of characters in s1 and track number of unique characters.
- Initialize sliding window frequency counts and a match count.
- Expand window by adding characters and update match count when frequencies match.
- Shrink window by removing characters and update match count accordingly.
- If match count equals unique character count, return true.
- Return false if no valid window found.
💡 The challenge is carefully updating match count to reflect exact frequency matches without full array comparisons.
def checkInclusion(s1: str, s2: str) -> bool:
len_s1, len_s2 = len(s1), len(s2)
if len_s1 > len_s2:
return False
count = [0] * 26
for c in s1:
count[ord(c) - ord('a')] += 1
left = 0
right = 0
required = sum(1 for x in count if x > 0)
formed = 0
window_count = [0] * 26
while right < len_s2:
idx = ord(s2[right]) - ord('a')
window_count[idx] += 1
if window_count[idx] == count[idx]:
formed += 1
if right - left + 1 > len_s1:
left_idx = ord(s2[left]) - ord('a')
if window_count[left_idx] == count[left_idx]:
formed -= 1
window_count[left_idx] -= 1
left += 1
if formed == required:
return True
right += 1
return False
# Driver code
if __name__ == "__main__":
print(checkInclusion("ab", "eidbaooo")) # True
print(checkInclusion("ab", "eidboaoo")) # False
Line Notes
count = [0] * 26Frequency array for s1 characters.
required = sum(1 for x in count if x > 0)Count how many unique characters need to match.
window_count = [0] * 26Frequency array for current window in s2.
while right < len_s2:Expand window by moving right pointer.
window_count[idx] += 1Add frequency of new character entering window.
if window_count[idx] == count[idx]: formed += 1Increment formed when a character frequency matches exactly.
if right - left + 1 > len_s1:Shrink window if it exceeds s1 length.
if window_count[left_idx] == count[left_idx]: formed -= 1Decrement formed when frequency no longer matches before removing character.
window_count[left_idx] -= 1Remove frequency of character leaving window.
left += 1Move left pointer to shrink window.
if formed == required: return TrueIf all characters match required frequency, return true.
public class Solution {
public static boolean checkInclusion(String s1, String s2) {
int lenS1 = s1.length(), lenS2 = s2.length();
if (lenS1 > lenS2) return false;
int[] count = new int[26];
for (char c : s1.toCharArray()) count[c - 'a']++;
int required = 0;
for (int c : count) if (c > 0) required++;
int[] windowCount = new int[26];
int formed = 0, left = 0, right = 0;
while (right < lenS2) {
int idx = s2.charAt(right) - 'a';
windowCount[idx]++;
if (windowCount[idx] == count[idx]) formed++;
if (right - left + 1 > lenS1) {
int leftIdx = s2.charAt(left) - 'a';
if (windowCount[leftIdx] == count[leftIdx]) formed--;
windowCount[leftIdx]--;
left++;
}
if (formed == required) return true;
right++;
}
return false;
}
public static void main(String[] args) {
System.out.println(checkInclusion("ab", "eidbaooo")); // true
System.out.println(checkInclusion("ab", "eidboaoo")); // false
}
}
Line Notes
int[] count = new int[26];Frequency array for s1 characters.
int required = 0; for (int c : count) if (c > 0) required++;Count unique characters to match.
int[] windowCount = new int[26];Frequency array for current window in s2.
while (right < lenS2)Expand window by moving right pointer.
windowCount[idx]++;Add frequency of new character entering window.
if (windowCount[idx] == count[idx]) formed++;Increment formed when frequency matches exactly.
if (right - left + 1 > lenS1)Maintain window size equal to s1 length.
if (windowCount[leftIdx] == count[leftIdx]) formed--;Decrement formed when frequency no longer matches before removing character.
windowCount[leftIdx]--;Remove frequency of character leaving window.
left++;Move left pointer to shrink window.
if (formed == required) return true;If all characters match required frequency, return true.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
bool checkInclusion(string s1, string s2) {
int lenS1 = s1.size(), lenS2 = s2.size();
if (lenS1 > lenS2) return false;
vector<int> count(26, 0), windowCount(26, 0);
for (char c : s1) count[c - 'a']++;
int required = 0;
for (int c : count) if (c > 0) required++;
int formed = 0, left = 0, right = 0;
while (right < lenS2) {
int idx = s2[right] - 'a';
windowCount[idx]++;
if (windowCount[idx] == count[idx]) formed++;
if (right - left + 1 > lenS1) {
int leftIdx = s2[left] - 'a';
if (windowCount[leftIdx] == count[leftIdx]) formed--;
windowCount[leftIdx]--;
left++;
}
if (formed == required) return true;
right++;
}
return false;
}
int main() {
cout << boolalpha << checkInclusion("ab", "eidbaooo") << endl; // true
cout << boolalpha << checkInclusion("ab", "eidboaoo") << endl; // false
return 0;
}
Line Notes
vector<int> count(26, 0), windowCount(26, 0);Frequency vectors for s1 and current window.
int required = 0; for (int c : count) if (c > 0) required++;Count unique characters to match.
int formed = 0, left = 0, right = 0;Initialize pointers and formed count.
while (right < lenS2)Expand window by moving right pointer.
windowCount[idx]++;Add frequency of new character entering window.
if (windowCount[idx] == count[idx]) formed++;Increment formed when frequency matches exactly.
if (right - left + 1 > lenS1)Keep window size fixed to s1 length.
if (windowCount[leftIdx] == count[leftIdx]) formed--;Decrement formed when frequency no longer matches before removing character.
windowCount[leftIdx]--;Remove frequency of character leaving window.
left++;Move left pointer to shrink window.
if (formed == required) return true;If all characters match required frequency, return true.
function checkInclusion(s1, s2) {
const lenS1 = s1.length, lenS2 = s2.length;
if (lenS1 > lenS2) return false;
const count = Array(26).fill(0);
for (const c of s1) count[c.charCodeAt(0) - 97]++;
let required = count.filter(x => x > 0).length;
const windowCount = Array(26).fill(0);
let formed = 0, left = 0, right = 0;
while (right < lenS2) {
let idx = s2.charCodeAt(right) - 97;
windowCount[idx]++;
if (windowCount[idx] === count[idx]) formed++;
if (right - left + 1 > lenS1) {
let leftIdx = s2.charCodeAt(left) - 97;
if (windowCount[leftIdx] === count[leftIdx]) formed--;
windowCount[leftIdx]--;
left++;
}
if (formed === required) return true;
right++;
}
return false;
}
// Test cases
console.log(checkInclusion("ab", "eidbaooo")); // true
console.log(checkInclusion("ab", "eidboaoo")); // false
Line Notes
const count = Array(26).fill(0);Frequency array for s1 characters.
let required = count.filter(x => x > 0).length;Count unique characters to match.
const windowCount = Array(26).fill(0);Frequency array for current window in s2.
let formed = 0, left = 0, right = 0;Initialize pointers and formed count.
while (right < lenS2)Expand window by moving right pointer.
windowCount[idx]++;Add frequency of new character entering window.
if (windowCount[idx] === count[idx]) formed++;Increment formed when frequency matches exactly.
if (right - left + 1 > lenS1)Maintain window size equal to s1 length.
if (windowCount[leftIdx] === count[leftIdx]) formed--;Decrement formed when frequency no longer matches before removing character.
windowCount[leftIdx]--;Remove frequency of character leaving window.
left++;Move left pointer to shrink window.
if (formed === required) return true;If all characters match required frequency, return true.
TimeO(n) where n = len(s2)
SpaceO(1) fixed size arrays for frequency counts
Each character is processed once, and match count updates are constant time, avoiding full array comparisons.
💡 This approach is the most efficient and elegant for large inputs.
Interview Verdict: Accepted
This is the optimal approach to implement in interviews for this problem.