Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,7 @@
* [Happy Number](maths/special_numbers/happy_number.py)
* [Harshad Numbers](maths/special_numbers/harshad_numbers.py)
* [Hexagonal Number](maths/special_numbers/hexagonal_number.py)
* [Jacobsthal Number](maths/special_numbers/jacobsthal_number.py)
* [Kaprekar Constant](maths/special_numbers/kaprekar_constant.py)
* [Kaprekar Number](maths/special_numbers/kaprekar_number.py)
* [Krishnamurthy Number](maths/special_numbers/krishnamurthy_number.py)
Expand Down Expand Up @@ -1602,6 +1603,7 @@
* [Lower](strings/lower.py)
* [Manacher](strings/manacher.py)
* [Min Cost String Conversion](strings/min_cost_string_conversion.py)
* [Min Window Substring](strings/min_window_substring.py)
* [Naive String Search](strings/naive_string_search.py)
* [Ngram](strings/ngram.py)
* [Palindrome](strings/palindrome.py)
Expand Down
89 changes: 89 additions & 0 deletions strings/min_window_substring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
def min_window(search_str: str, target_letters: str) -> str:
"""
Given a string to search, and another string of target char_dict,
return the smallest substring of the search string that contains
all target char_dict.

This is somewhat modified from my solution to the problem
"Minimum Window Substring" on leetcode.
https://leetcode.com/problems/minimum-window-substring/description/

>>> min_window("Hello World", "lWl")
'llo W'
>>> min_window("Hello World", "f")
''

This solution uses a sliding window, alternating between shifting
the end of the window right until all target char_dict are contained
in the window, and shifting the start of the window right until the
window no longer contains every target character.

Time complexity: O(target_count + search_len) ->
The algorithm checks a dictionary at most twice for each character
in search_str.

Space complexity: O(search_len) ->
The primary contributor to additional space is the building of a
dictionary using the search string.
"""

target_count = len(target_letters)
search_len = len(search_str)

# Return if not possible due to string lengths.
if search_len < target_count:
return ""

# Build dictionary with counts for each letter in target_letters
char_dict = {}
for ch in target_letters:
if ch not in char_dict:
char_dict[ch] = 1
else:
char_dict[ch] += 1

# Initialize window
window_start = 0
window_end = 0

exists = False
min_window_len = search_len + 1

# Start sliding window algorithm
while window_end < search_len:
# Slide window end right until all search characters are contained
while target_count > 0 and window_end < search_len:
cur = search_str[window_end]
if cur in char_dict:
char_dict[cur] -= 1
if char_dict[cur] >= 0:
target_count -= 1
window_end += 1
temp = window_end - window_start

# Check if window is the smallest found so far
if target_count == 0 and temp < min_window_len:
min_window = [window_start, window_end]
exists = True
min_window_len = temp

# Slide window start right until a search character exits the window
while target_count == 0 and window_start < window_end:
cur = search_str[window_start]
window_start += 1
if cur in char_dict:
char_dict[cur] += 1
if char_dict[cur] > 0:
break
temp = window_end - window_start + 1

# Check if window is the smallest found so far
if temp < min_window_len and target_count == 0:
min_window = [window_start - 1, window_end]
min_window_len = temp
target_count = 1

if exists:
return search_str[min_window[0] : min_window[1]]
else:
return ""
Loading