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 "ba" which is a permutation of s1
Example 2:
Input: s1 = "ab", s2 = "eidboaoo"
Output: false
A permutation means the characters are the same, just in different order. So we need to find a substring in s2 that has the exact same character frequencies as s1.
Use a sliding window of size len(s1) and compare character frequencies.
s1len(s1) through s2s1 frequenciesdef checkInclusion(s1, s2):
if len(s1) > len(s2):
return False
s1_count = {}
s2_count = {}
# Count characters in s1
for c in s1:
s1_count[c] = s1_count.get(c, 0) + 1
# Initial window in s2
for i in range(len(s1)):
s2_count[s2[i]] = s2_count.get(s2[i], 0) + 1
# Check initial window
if s1_count == s2_count:
return True
# Slide window
for i in range(len(s1), len(s2)):
# Add new character
s2_count[s2[i]] = s2_count.get(s2[i], 0) + 1
# Remove old character
left_char = s2[i - len(s1)]
s2_count[left_char] -= 1
if s2_count[left_char] == 0:
del s2_count[left_char]
# Check if match
if s1_count == s2_count:
return True
return False
For s1 = "ab", s2 = "eidbaooo":
s1_count = {a:1, b:1}
Window "ei": {e:1, i:1} ✗
Window "id": {i:1, d:1} ✗
Window "db": {d:1, b:1} ✗
Window "ba": {b:1, a:1} ✓ MATCH!
Instead of comparing maps, count how many characters have matching frequencies.
def checkInclusion(s1, s2):
if len(s1) > len(s2):
return False
s1_count = [0] * 26
s2_count = [0] * 26
for c in s1:
s1_count[ord(c) - ord('a')] += 1
matches = 0
for i in range(26):
if s1_count[i] == s2_count[i]:
matches += 1
for i in range(len(s2)):
if matches == 26:
return True
# Add right character
idx = ord(s2[i]) - ord('a')
s2_count[idx] += 1
if s2_count[idx] == s1_count[idx]:
matches += 1
elif s2_count[idx] == s1_count[idx] + 1:
matches -= 1
# Remove left character
if i >= len(s1):
idx = ord(s2[i - len(s1)]) - ord('a')
s2_count[idx] -= 1
if s2_count[idx] == s1_count[idx]:
matches += 1
elif s2_count[idx] == s1_count[idx] - 1:
matches -= 1
return matches == 26
Same complexity, but avoids repeated map comparisons.
1/**
2 * Permutation in String
3 * Time: O(n) where n = len(s2)
4 * Space: O(1) - at most 26 characters
5 */
6
7import java.util.*;
8
9// Approach 1: Sliding Window with Frequency Arrays
10class Solution {
11 public boolean checkInclusion(String s1, String s2) {
12 if (s1.length() > s2.length()) {
13 return false;
14 }
15
16 int[] s1_count = new int[26];
17 int[] s2_count = new int[26];
18
19 // Count s1 characters
20 for (char c : s1.toCharArray()) {
21 s1_count[c - 'a']++;
22 }
23
24 // Initial window
25 for (int i = 0; i < s1.length(); i++) {
26 s2_count[s2.charAt(i) - 'a']++;
27 }
28
29 // Check initial window
30 if (Arrays.equals(s1_count, s2_count)) {
31 return true;
32 }
33
34 // Slide window
35 for (int i = s1.length(); i < s2.length(); i++) {
36 // Add new character
37 s2_count[s2.charAt(i) - 'a']++;
38
39 // Remove old character
40 s2_count[s2.charAt(i - s1.length()) - 'a']--;
41
42 // Check if match
43 if (Arrays.equals(s1_count, s2_count)) {
44 return true;
45 }
46 }
47
48 return false;
49 }
50}
51
52// Approach 2: Match Counter (Optimized)
53class Solution2 {
54 public boolean checkInclusion(String s1, String s2) {
55 if (s1.length() > s2.length()) {
56 return false;
57 }
58
59 int[] s1_count = new int[26];
60 int[] s2_count = new int[26];
61
62 for (char c : s1.toCharArray()) {
63 s1_count[c - 'a']++;
64 }
65
66 int matches = 0;
67 for (int i = 0; i < 26; i++) {
68 if (s1_count[i] == s2_count[i]) {
69 matches++;
70 }
71 }
72
73 for (int i = 0; i < s2.length(); i++) {
74 if (matches == 26) {
75 return true;
76 }
77
78 // Add right character
79 int idx = s2.charAt(i) - 'a';
80 s2_count[idx]++;
81 if (s2_count[idx] == s1_count[idx]) {
82 matches++;
83 } else if (s2_count[idx] == s1_count[idx] + 1) {
84 matches--;
85 }
86
87 // Remove left character
88 if (i >= s1.length()) {
89 idx = s2.charAt(i - s1.length()) - 'a';
90 s2_count[idx]--;
91 if (s2_count[idx] == s1_count[idx]) {
92 matches++;
93 } else if (s2_count[idx] == s1_count[idx] - 1) {
94 matches--;
95 }
96 }
97 }
98
99 return matches == 26;
100 }
101}
102