Permutation in String
Given strings s1 and s2, return true if s2 contains a permutation of s1 as a contiguous substring . Slide a fixed-size window of length s1 across s2 and compare letter frequency counts as one character leaves and another enters.
Constraints
- 1 ≤ s1.length, s2.length ≤ 104
- s1 and s2 consist of lowercase English letters
Example
s1 = "ab", s2 = "eidbaooo"trueExplanation "ba" is a permutation of "ab" and appears in s2.
In plain terms
- Permutation
- A rearrangement of all the letters in a word or phrase, using each one exactly once — 'ab' and 'ba' are permutations of each other.
Fixed window matching s1 letter counts
Window "ei" — counts do not match need {a:1,b:1}.
What happens in this step
window = [0, 1] ("ei") need = {a:1, b:1}
built from s2[0..1]:
window = {e:1, i:1}
window counts {e:1, i:1} don't match need {a:1, b:1} — no permutation here yet.Steps to visualize
- Build need counts from s1 and a same-size window over the start of s2.
- If the window letter counts match need, return true.
- Slide one step: increment the entering char, decrement the leaving char.
- Compare counts after each slide.
- Return false if no window ever matches.
Walk through the code
Same walkthrough, now with the code. Press Next to move one step and watch which lines run.
Window "ei" — counts do not match need {a:1,b:1}.
What happens in this step
window = [0, 1] ("ei") need = {a:1, b:1}
built from s2[0..1]:
window = {e:1, i:1}
window counts {e:1, i:1} don't match need {a:1, b:1} — no permutation here yet.Solution
function checkInclusion(s1, s2) {
const n = s1.length;
const m = s2.length;
if (n > m) return false;
const need = new Array(26).fill(0);
const window = new Array(26).fill(0);
const a = 'a'.charCodeAt(0);
for (let i = 0; i < n; i++) {
need[s1.charCodeAt(i) - a]++;
window[s2.charCodeAt(i) - a]++;
}
const matches = () => {
for (let i = 0; i < 26; i++) {
if (need[i] !== window[i]) return false;
}
return true;
};
if (matches()) return true;
for (let right = n; right < m; right++) {
window[s2.charCodeAt(right) - a]++;
const left = right - n;
window[s2.charCodeAt(left) - a]--;
if (matches()) return true;
}
return false;
}- Time
- O(n)
- Space
- O(1)
Test cases
| Input | Expected | Covers |
|---|---|---|
s1 = "ab", s2 = "eidbaooo" | true | Docstring example — "ba" is a permutation |
s1 = "a", s2 = "a" | true | Smallest valid input |
s1 = "abc", s2 = "bca" | true | Entire s2 is a permutation of s1 |
s1 = "ab", s2 = "eidboaoo" | false | No valid window exists |
s1 = "aaa", s2 = "aaaaa" | true | All identical characters with exact count match |
s1 = "abcd", s2 = "abc" | false | s1 longer than s2 |
s1 = "abc", s2 = "xyzxycab" | true | Permutation "cab" appears later in s2 |