diff --git a/0567_permutation-in-string/README.md b/0567_permutation-in-string/README.md new file mode 100644 index 0000000..753b32a --- /dev/null +++ b/0567_permutation-in-string/README.md @@ -0,0 +1,23 @@ +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 + + +**Constraints:** + +* `1 <= s1.length, s2.length <= 104` +* `s1` and `s2` consist of lowercase English letters. + +https://leetcode.com/problems/permutation-in-string \ No newline at end of file diff --git a/0567_permutation-in-string/python3/hashmaps_in_loop.py b/0567_permutation-in-string/python3/hashmaps_in_loop.py new file mode 100644 index 0000000..34d2b8b --- /dev/null +++ b/0567_permutation-in-string/python3/hashmaps_in_loop.py @@ -0,0 +1,31 @@ +# Time: O(S1 · S2) ; S2 is len(s1) and S2 is len(S2) +# Space: O(S2 · 26) + +from collections import Counter + +class Solution: + def checkInclusion(self, s1: str, s2: str) -> bool: + if len(s1) > len(s2): return False + + if len(s1) == len(s2): + return Counter(s1) == Counter(s2) + + s1_counter = Counter(s1) + + target_length = len(s1) + end = target_length - 1 + + while end < len(s2): + start = end - target_length + 1 + curr_substring = s2[start:end + 1] + + # Check if counters match for the given substring + # indicated by start:end with a length of target_length + if s1_counter == Counter(curr_substring): + return True + + end += 1 + + return False + + \ No newline at end of file diff --git a/0567_permutation-in-string/python3/solution.py b/0567_permutation-in-string/python3/solution.py new file mode 100644 index 0000000..f9e4b62 --- /dev/null +++ b/0567_permutation-in-string/python3/solution.py @@ -0,0 +1,70 @@ +class Solution: + def checkInclusion(self, s1: str, s2: str) -> bool: + ''' + Sliding window, better space utilization + ''' + + if len(s1) > len(s2): return False + + def get_letter_index(letter): + ''' + Problem only concerns with lowercase letters + ''' + return ord(letter) - ord('a') + + + s1_count, s2_count = [0] * 26, [0] * 26 + for i in range(len(s1)): + s1_count[get_letter_index(s1[i])] += 1 + s2_count[get_letter_index(s2[i])] += 1 + + # Keep a `count_matches` variable that tells us how many + # counts of a-z from s1 match a-z in the window of s2 + count_matches = 0 + + for i in range(26): + if s1_count[i] == s2_count[i]: + count_matches += 1 + + # It's possible that we get a perfect match right after the + # above initial computation. If yes, yay! + if count_matches == 26: + return True + + + # Start from the very next character after figuring out the + # initial `count_matches` value which would be at len(s1) + l = 0 + for r in range(len(s1), len(s2)): + # + # Adding rightmost letter + # + li = get_letter_index(s2[r]) + s2_count[li] += 1 + + if s1_count[li] == s2_count[li]: + count_matches += 1 + # If after adding new right letter, count increased by 1 for + # the letter index, then that means total matches also reduced + # by 1 + elif s1_count[li] + 1 == s2_count[li]: + count_matches -= 1 + + # + # Removing leftmost letter + # + li = get_letter_index(s2[l]) + s2_count[li] -= 1 + + if s1_count[li] == s2_count[li]: + count_matches += 1 + # If after removing leftmost letter, count decreased by 1, then + # our total matches also reduced by 1 + elif s1_count[li] - 1 == s2_count[li]: + count_matches -= 1 + + if count_matches == 26: return True + + l += 1 + + return count_matches == 26