Permutation in String
Permutation in String
š§© Problem Statement
Given two strings s1 and s2, return true if s2 contains a permutation of s1, or false otherwise.
In other words, return true if one of s1's permutations is the substring of s2.
š¹ Example 1:
Input:
s1 = "ab", s2 = "eidbaooo"
Output:
true
Explanation:
s2 contains one permutation of s1 ("ba").
š¹ Example 2:
Input:
s1 = "ab", s2 = "eidboaoo"
Output:
false
š Approaches
1. Sliding Window with Frequency Array
A permutation of s1 means a string with the same characters with the same frequencies.
The problem is equivalent to: Find if s2 has a substring of length len(s1) with the same character counts.
We use a fixed-size sliding window of size len(s1).
- Maintain a frequency array (or hash map) for
s1. - Maintain a frequency array for the current window in
s2. - As we slide the window:
- Add the new character on the right.
- Remove the old character on the left.
- Check if the two frequency arrays match.
⨠Intuition
Instead of generating all permutations (factorial complexity), we just check character "fingerprints". If the sorted versions (or count maps) match, it's a permutation. Since sorting is $O(k \log k)$, and counting is $O(k)$, counting is faster for checking every window.
š„ Algorithm Steps
- Lengths:
m = len(s1),n = len(s2). Ifm > n, returnfalse. - Count freqs of
s1and firstmchars ofs2. - If
freq1 == freq2, returntrue. - Iterate
ifrommton - 1:
- Add
s2[i]tofreq2. - Remove
s2[i - m]fromfreq2. - If
freq1 == freq2, returntrue.
- Return
false.
ā³ Time & Space Complexity
- Time Complexity: $O(n)$ or $O(26 \cdot n)$. Comparing arrays of size 26 is $O(1)$.
- Space Complexity: $O(1)$ (since map size is fixed at 26).
š Code Implementations
C++
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if (s1.length() > s2.length()) return false;
vector<int> s1Count(26, 0);
vector<int> s2Count(26, 0);
for (int i = 0; i < s1.length(); i++) {
s1Count[s1[i] - 'a']++;
s2Count[s2[i] - 'a']++;
}
if (s1Count == s2Count) return true;
for (int i = s1.length(); i < s2.length(); i++) {
s2Count[s2[i] - 'a']++;
s2Count[s2[i - s1.length()] - 'a']--;
if (s1Count == s2Count) return true;
}
return false;
}
};
Python
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
if len(s1) > len(s2):
return False
s1_count = [0] * 26
s2_count = [0] * 26
# Initialize
for i in range(len(s1)):
s1_count[ord(s1[i]) - ord('a')] += 1
s2_count[ord(s2[i]) - ord('a')] += 1
if s1_count == s2_count:
return True
# Slide
for i in range(len(s1), len(s2)):
s2_count[ord(s2[i]) - ord('a')] += 1
s2_count[ord(s2[i - len(s1)]) - ord('a')] -= 1
if s1_count == s2_count:
return True
return False
Java
import java.util.Arrays;
class Solution {
public boolean checkInclusion(String s1, String s2) {
if (s1.length() > s2.length()) return false;
int[] s1Count = new int[26];
int[] s2Count = new int[26];
for (int i = 0; i < s1.length(); i++) {
s1Count[s1.charAt(i) - 'a']++;
s2Count[s2.charAt(i) - 'a']++;
}
if (Arrays.equals(s1Count, s2Count)) return true;
for (int i = s1.length(); i < s2.length(); i++) {
s2Count[s2.charAt(i) - 'a']++;
s2Count[s2.charAt(i - s1.length()) - 'a']--;
if (Arrays.equals(s1Count, s2Count)) return true;
}
return false;
}
}
š Real-World Analogy
ID Badge scanner:
You have a specific ID code (s1). The scanner reads a continuous stream of data (s2). It needs to detect if the ID code appears anywhere in the stream, but the order of matched bytes doesn't matter (permutation), only their presence and counts count.
šÆ Summary
ā
Fixed Size: Window size is always len(s1).
ā
Fingerprint: Use frequency arrays to represent "content" regardless of order.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if (s1.length() > s2.length())
return false;
vector<int> s1Count(26, 0);
vector<int> s2Count(26, 0);
for (int i = 0; i < s1.length(); i++) {
s1Count[s1[i] - 'a']++;
s2Count[s2[i] - 'a']++;
}
if (s1Count == s2Count)
return true;
for (int i = s1.length(); i < s2.length(); i++) {
s2Count[s2[i] - 'a']++;
s2Count[s2[i - s1.length()] - 'a']--;
if (s1Count == s2Count)
return true;
}
return false;
}
};
int main() {
Solution sol;
string s1 = "ab";
string s2 = "eidbaooo";
cout << "Contains Permutation 1: "
<< (sol.checkInclusion(s1, s2) ? "true" : "false")
<< endl; // Expected: true
s1 = "ab";
s2 = "eidboaoo";
cout << "Contains Permutation 2: "
<< (sol.checkInclusion(s1, s2) ? "true" : "false")
<< endl; // Expected: false
return 0;
}