Sliding Window · Medium
Count Anagram Substrings
Solve it on DeVert Campus - free code runner
Problem
You are given two lowercase strings s and p. Count how many substrings of s are anagrams of p, that is, count the number of starting positions in s at which the |p| characters that follow can be rearranged to exactly form p (matching every letter's frequency).
Input and output
Input: The first line contains the string s. The second line contains the string p.
Output: Print a single integer: the number of substrings of s that are anagrams of p.
Example
Input: cbaebabacd abc Output: 2
Constraints
1 <= |p| <= |s| <= 10^5
s and p consist only of lowercase English letters.
Key observation
This is the sliding-window sibling of 'Group Anagrams' and 'Anagram Check' from the Hashing category - all three rely on the same core insight that anagram-equality reduces to frequency-array equality, just applied in different contexts (grouping, single-pair checking, or windowed counting).
Intuition
Count how many substrings of a string are anagrams of a given pattern.
Brute force: For every window position, sort both the window's characters and p's characters and compare - this costs O(n * k log k), unnecessary when frequency arrays can be compared directly without sorting.
Optimised: Maintaining a running frequency array for the current window (updated incrementally as it slides, adding incoming and removing outgoing characters) avoids ever re-counting the whole window from scratch - comparing two fixed-size (26-element) frequency arrays for equality is O(26), effectively O(1), making the whole scan O(n) instead of O(n*k).
Step by step
1. Build a frequency array of the |p| characters in p, and maintain a frequency array of the CURRENT window of s (of the same length).
2. Slide the window one character at a time: ADD the incoming character's frequency and REMOVE the outgoing character's frequency.
3. Two frequency arrays represent an anagram match exactly when they're EQUAL element-for-element; compare them once per window position.
Complexity
Time: O(n * 26) which simplifies to O(n), since comparing two 26-element frequency arrays is a small constant amount of work per window.
Space: O(1) - the frequency arrays are always exactly 26 elements, regardless of string length.
Edge cases
Handle the case where |p| == |s| (there is exactly one substring to check) and the case where no substring of s matches (answer is 0).
Interview tip
Be ready to mention the alternative of tracking just a SINGLE 'number of matching frequency positions' counter (updated incrementally) instead of comparing full 26-element arrays every time - a further optimization that avoids even the small constant-factor array comparison.