|
| 1 | +# Permutation in String |
| 2 | + |
| 3 | +## Problem Description |
| 4 | + |
| 5 | +Given two strings `s1` and `s2`, return `true` if `s2` contains a permutation of `s1`, |
| 6 | +or `false` otherwise. |
| 7 | + |
| 8 | +In other words, return `true` if one of `s1`'s permutations is the substring of `s2`. |
| 9 | + |
| 10 | +**Example 1:** |
| 11 | + |
| 12 | +* Input: `s1 = "ab", s2 = "eidbaooo"` |
| 13 | +* Output: `true` |
| 14 | +* Explanation: `s2` contains one permutation of `s1` (`"ba"`). |
| 15 | + |
| 16 | +**Example 2:** |
| 17 | + |
| 18 | +* Input: `s1 = "ab", s2 = "eidboaoo"` |
| 19 | +* Output: `false` |
| 20 | + |
| 21 | +**Constraints:** |
| 22 | + |
| 23 | +* `1 <= s1.length, s2.length <= 10^4` |
| 24 | +* `s1` and `s2` consist of lowercase English letters. |
| 25 | + |
| 26 | +## Solution |
| 27 | + |
| 28 | +```python |
| 29 | +def check_inclusion(s1: str, s2: str) -> bool: |
| 30 | + """ |
| 31 | + Check if any permutation of s1 exists as a substring in s2. |
| 32 | +
|
| 33 | + This function uses a sliding window approach with hash maps to efficiently |
| 34 | + track character counts and determine if any permutation of s1 is present in s2. |
| 35 | +
|
| 36 | + :param s1: The string whose permutations we want to find in s2. |
| 37 | + :param s2: The string in which we're searching for permutations of s1. |
| 38 | + :return: True if any permutation of s1 is found as a substring in s2, False otherwise. |
| 39 | + """ |
| 40 | + pattern_hash = {} |
| 41 | + for character in s1: |
| 42 | + if character not in pattern_hash: |
| 43 | + pattern_hash[character] = 1 |
| 44 | + else: |
| 45 | + pattern_hash[character] += 1 |
| 46 | + |
| 47 | + hash_copy = pattern_hash.copy() |
| 48 | + pattern_length = len(s1) |
| 49 | + |
| 50 | + for index in range(len(s2)): |
| 51 | + if index >= pattern_length: |
| 52 | + outgoing_character = s2[index - pattern_length] |
| 53 | + if outgoing_character in pattern_hash: |
| 54 | + if outgoing_character not in hash_copy: |
| 55 | + hash_copy[outgoing_character] = 1 |
| 56 | + else: |
| 57 | + hash_copy[outgoing_character] += 1 |
| 58 | + if hash_copy[outgoing_character] == 0: |
| 59 | + del hash_copy[outgoing_character] |
| 60 | + |
| 61 | + incoming_character = s2[index] |
| 62 | + if incoming_character in pattern_hash: |
| 63 | + if incoming_character in hash_copy: |
| 64 | + hash_copy[incoming_character] -= 1 |
| 65 | + else: |
| 66 | + hash_copy[incoming_character] = -1 |
| 67 | + if hash_copy[incoming_character] == 0: |
| 68 | + del hash_copy[incoming_character] |
| 69 | + if len(hash_copy) == 0: |
| 70 | + return True |
| 71 | + return False |
| 72 | +``` |
| 73 | + |
| 74 | +* **Time Complexity:** $O(n)$ |
| 75 | +* **Space Complexity:** $O(1)$ |
| 76 | + |
| 77 | +## Explanation of the Solution |
| 78 | + |
| 79 | +The problem reduces to finding a window in `s2` where the character frequency exactly matches that of `s1` |
| 80 | +(regardless of order). This is equivalent to checking for an anagram of `s1` in `s2`. |
| 81 | + |
| 82 | +1. Frequency Map for s1 (pattern_hash) |
| 83 | + * Create a hash map counting occurrences of each character in `s1`. |
| 84 | +2. Sliding Window over s2 |
| 85 | + * Traverse `s2` while maintaining a dynamically adjusted window of size `len(s1)`. |
| 86 | + * Use a copy of `pattern_hash` (`hash_copy`) to track how much the current window deviates from `s1`'s frequencies. |
| 87 | + * Goal: `hash_copy` becomes empty when the window matches `s1`'s frequencies. |
| 88 | +3. Window Adjustment Logic |
| 89 | + * For each new character (incoming_character): |
| 90 | + * If it exists in `pattern_hash`, decrement its count in `hash_copy`. |
| 91 | + * If a count reaches 0, remove the key (indicates balance with `s1`). |
| 92 | + * For the character exiting the window (outgoing_character): |
| 93 | + * Re-increment its count in `hash_copy` (reversing the earlier decrement). |
| 94 | + * Remove the key if the count rebalances to 0. |
| 95 | +4. Check for Permutation |
| 96 | + * If `hash_copy` is ever empty, the current window is a permutation of `s1` → return `True`. |
| 97 | + * If the loop ends without finding such a window → return `False`. |
0 commit comments