Skip to content

Sliding Window — Permutation in String ​

↗ LeetCode: Permutation in String · Medium · pattern chapter →

Asked atMetaGoogleMicrosoftAmazonApple

Given strings s1 and s2, return true iff s2 contains any permutation of s1 as a substring.

Example 1 — s1 = "ab", s2 = "eidbaooo" → true ("ba" is a permutation of "ab") Example 2 — s1 = "ab", s2 = "eidboaoo" → falseExample 3 — s1 = "adc", s2 = "dcda" → true ("dca" at index 0)

Constraints — 1 ≤ |s1|, |s2| ≤ 10⁴. Lowercase English. Brute compares every window against sorted target — O(n·k·log k) = 10⁴·10⁴·13 ≈ 1.3·10⁹ ops (TLE). Sliding-window frequency compare is O(n·26) = ~2·10⁵ ops.

Progressive Hints
Try to solve it yourself first. Reveal hints only when stuck — each hint is progressively more specific.
---
⏱️Interview timer00:00
Practice under interview pressure. Start when you begin reading; stop when you finish. Save best only when you had a full working solution.
Target for interview: Medium = 20-25 min · Hard = 30-40 min · Best time persists on this device only.

Approach 1 — Sort every window ​

Intuition. Slide a window of size |s1| over s2; sort each and compare to sorted s1.

java
boolean checkInclusionBrute(String s1, String s2) {
    int k = s1.length();
    if (k > s2.length()) return false;
    char[] a = s1.toCharArray();
    Arrays.sort(a);
    String target = new String(a);
    for (int i = 0; i + k <= s2.length(); i++) {
        char[] w = s2.substring(i, i + k).toCharArray();
        Arrays.sort(w);
        if (target.equals(new String(w))) return true;
    }
    return false;
}
Execution Trace
Brute — s1='ab', s2='eidbaooo'
ie0i1d2b3a4o5o6o7window = eisorted = eitarget = ab
Step 1 / 3no match

Complexity — Time O((n − k) · k log k); Space O(k) per window.


Approach 2 — Fixed window with frequency array ​

Insight from brute. Sorting is overkill — we just need the multiset. A 26-int frequency count is enough. Compare need[] vs current have[] at every position.

java
boolean checkInclusionEq(String s1, String s2) {
    int k = s1.length();
    if (k > s2.length()) return false;
    int[] need = new int[26], have = new int[26];
    for (char c : s1.toCharArray()) need[c - 'a']++;
    for (int i = 0; i < s2.length(); i++) {
        have[s2.charAt(i) - 'a']++;
        if (i >= k) have[s2.charAt(i - k) - 'a']--;
        if (i >= k - 1 && Arrays.equals(need, have)) return true;
    }
    return false;
}
Execution Trace
Fixed window + Arrays.equals — s1='ab', s2='eidbaooo'
leftrighte0i1d2b3a4o5o6o7have = {e:1,i:1}need = {a:1,b:1}
Step 1 / 3not equal

Complexity — Time O((n − k) · 26); Space O(1).


Approach 3 — Running match counter (O(1) per step) ​

Insight from previous. Arrays.equals costs 26 per position. Maintain a matches counter: for each of the 26 letters, track whether have[c] == need[c]. Increment/decrement matches incrementally on every add/remove.

java
boolean checkInclusion(String s1, String s2) {
    int k = s1.length();
    if (k > s2.length()) return false;
    int[] need = new int[26], have = new int[26];
    for (char c : s1.toCharArray()) need[c - 'a']++;
    int matches = 0;
    for (int i = 0; i < 26; i++) if (need[i] == 0) matches++;
    for (int i = 0; i < s2.length(); i++) {
        int r = s2.charAt(i) - 'a';
        have[r]++;
        if (have[r] == need[r]) matches++;
        else if (have[r] == need[r] + 1) matches--;
        if (i >= k) {
            int l = s2.charAt(i - k) - 'a';
            have[l]--;
            if (have[l] == need[l]) matches++;
            else if (have[l] == need[l] - 1) matches--;
        }
        if (matches == 26) return true;
    }
    return false;
}
Execution Trace
Running match — s1='ab', s2='eidbaooo'
leftrighte0i1d2b3a4o5o6o7matches = 24
Step 1 / 324 letters already match (0=0); 2 mismatches (a, b)

Complexity — Time O(n) — O(1) per position; Space O(1).


Try it yourself ​

Complexity summary ​

ApproachTimeSpaceInterview grade
Sort every windowO((n−k) · k log k)O(k)brute; correct baseline
Fixed window + Arrays.equalsO((n−k) · 26)O(1)acceptable, since 26 is a constant
Running match counterO(n)O(1)polish — mention if asked to justify

When to use which ​

  • Anagram / multi-set check → fixed window + frequency array is the canonical answer.
  • Interviewer asks "can you do without the 26 factor?" → running match counter.
  • Unicode alphabet → use HashMap<Character,Integer>; running-match trick still applies with slightly more bookkeeping.
  • Return all match indices → this is Find All Anagrams in a String.
✨AI Study CompanionBeta
Was this page helpful?

Released under MIT license.

💡 Quick shortcuts
H HintsR Run JavaA AI Help