From 16cc63f870cd5035b05520b3061d8cc64709d479 Mon Sep 17 00:00:00 2001 From: tom4649 Date: Thu, 4 Jun 2026 07:06:08 +0900 Subject: [PATCH 1/4] 76. Minimum Window Substring --- 0076.Minimum-Window-Substring/memo.md | 31 +++++++++++ 0076.Minimum-Window-Substring/step1.py | 48 +++++++++++++++++ .../step1_revised.py | 51 +++++++++++++++++++ 0076.Minimum-Window-Substring/step2.py | 38 ++++++++++++++ 0076.Minimum-Window-Substring/step3.py | 40 +++++++++++++++ 5 files changed, 208 insertions(+) create mode 100644 0076.Minimum-Window-Substring/memo.md create mode 100644 0076.Minimum-Window-Substring/step1.py create mode 100644 0076.Minimum-Window-Substring/step1_revised.py create mode 100644 0076.Minimum-Window-Substring/step2.py create mode 100644 0076.Minimum-Window-Substring/step3.py diff --git a/0076.Minimum-Window-Substring/memo.md b/0076.Minimum-Window-Substring/memo.md new file mode 100644 index 0000000..830dd26 --- /dev/null +++ b/0076.Minimum-Window-Substring/memo.md @@ -0,0 +1,31 @@ +# 76. Minimum Window Substring + +## step1 +32mほどで解いた。sliding windowを使えばO(n)で解けることにはすぐに気がついたが、処理をコードに変換するのに時間がかかった。最初の解法: step1.py + +おそらくこの問題の解法は sliding window を用いた用いたこの解法しかないのでは。あとは同じ解法で以下にコードを改善するか。 + + +## 他の人のコード +https://github.com/hayashi-ay/leetcode/pull/73 + +> 工夫すると毎回全ての文字のカウントを確認しなくて済むような方法があります。 + +たしかに最も単純なのは毎回全ての文字のカウントを確認する方法になるのか。 + +変数名はleft, rightがわかりやすい。 +書き方はright の for 文で回した方がわかりやすいな + +https://github.com/shining-ai/leetcode/pull/61 +条件を num_matches で管理するのはわかりやすい + +他に ord を用いて配列をdictの代わりに用いる方法がある + +https://github.com/potrue/leetcode/pull/67/changes + +## step2 +for 文で書き直す。他に、クラスを使ってwindow_infoを定義する工夫をした(大袈裟かもしれない)。 + +## step3 +書く + diff --git a/0076.Minimum-Window-Substring/step1.py b/0076.Minimum-Window-Substring/step1.py new file mode 100644 index 0000000..b6388c8 --- /dev/null +++ b/0076.Minimum-Window-Substring/step1.py @@ -0,0 +1,48 @@ +import collections + + +class Solution: + def minWindow(self, s: str, t: str) -> str: + counter_t = collections.Counter(t) + counter_window = collections.Counter(s) + for key, count in counter_t.items(): + if counter_window.get(key, 0) < count: + return "" + + first = 0 + while s[first] not in counter_t: + first += 1 + + last = len(s) - 1 + while first < last: + while s[last] not in counter_t: + last -= 1 + if counter_t[s[last]] >= counter_window[s[last]]: + break + counter_window[s[last]] -= 1 + last -= 1 + + min_window_first = first + min_window_last = last + min_window_size = last - first + 1 + while first < len(s) - 1: + if counter_window[s[first]] <= counter_t[s[first]]: + next_last = last + 1 + while next_last < len(s) and s[next_last] != s[first]: + counter_window[s[next_last]] += 1 + next_last += 1 + if next_last == len(s): + break + last = next_last + else: + counter_window[s[first]] -= 1 + + first += 1 + while s[first] not in counter_t: + first += 1 + if min_window_size > last - first + 1: + min_window_size = last - first + 1 + min_window_first = first + min_window_last = last + + return s[min_window_first : min_window_last + 1] diff --git a/0076.Minimum-Window-Substring/step1_revised.py b/0076.Minimum-Window-Substring/step1_revised.py new file mode 100644 index 0000000..ddfbf66 --- /dev/null +++ b/0076.Minimum-Window-Substring/step1_revised.py @@ -0,0 +1,51 @@ +import collections + + +class Solution: + def minWindow(self, s: str, t: str) -> str: + counter_t = collections.Counter(t) + counter_window = collections.defaultdict(int) + for c in s: + if c in counter_t: + counter_window[c] += 1 + for key, count in counter_t.items(): + if counter_window.get(key, 0) < count: + return "" + + first = 0 + while s[first] not in counter_t: + first += 1 + + last = len(s) - 1 + while first < last: + while s[last] not in counter_t: + last -= 1 + if counter_t[s[last]] >= counter_window[s[last]]: + break + counter_window[s[last]] -= 1 + last -= 1 + + min_window_first = first + min_window_last = last + min_window_size = last - first + 1 + while first < len(s) - 1: + if counter_window[s[first]] <= counter_t[s[first]]: + next_last = last + 1 + while next_last < len(s) and s[next_last] != s[first]: + counter_window[s[next_last]] += 1 + next_last += 1 + if next_last == len(s): + break + last = next_last + else: + counter_window[s[first]] -= 1 + + first += 1 + while s[first] not in counter_t: + first += 1 + if min_window_size > last - first + 1: + min_window_size = last - first + 1 + min_window_first = first + min_window_last = last + + return s[min_window_first : min_window_last + 1] diff --git a/0076.Minimum-Window-Substring/step2.py b/0076.Minimum-Window-Substring/step2.py new file mode 100644 index 0000000..6fa79f6 --- /dev/null +++ b/0076.Minimum-Window-Substring/step2.py @@ -0,0 +1,38 @@ +import collections +import math + + +class WindowInfo: + left = None + right = None + size = math.inf + + +class Solution: + def minWindow(self, s: str, t: str) -> str: + required_count = collections.Counter(t) + window_count = collections.defaultdict(int) + num_required_unique_chars = len(required_count) + num_formed_chars = 0 + + window_info = WindowInfo() + left = 0 + for right in range(len(s)): + window_count[s[right]] += 1 + if window_count[s[right]] == required_count.get(s[right], -1): + num_formed_chars += 1 + + while num_formed_chars == num_required_unique_chars: + if window_info.size > right - left + 1: + window_info.size = right - left + 1 + window_info.left = left + window_info.right = right + + window_count[s[left]] -= 1 + if window_count[s[left]] < required_count.get(s[left], -1): + num_formed_chars -= 1 + left += 1 + + if math.isinf(window_info.size): + return "" + return s[window_info.left : window_info.right + 1] diff --git a/0076.Minimum-Window-Substring/step3.py b/0076.Minimum-Window-Substring/step3.py new file mode 100644 index 0000000..9765d0f --- /dev/null +++ b/0076.Minimum-Window-Substring/step3.py @@ -0,0 +1,40 @@ +import collections +import math + + +class WindowInfo: + left = None + right = None + size = math.inf + + +class Solution: + def minWindow(self, s: str, t: str) -> str: + required_count = collections.Counter(t) + window_count = collections.defaultdict(int) + num_required_count = len(required_count) + num_formed_count = 0 + window_info = WindowInfo() + + left = 0 + for right in range(len(s)): + window_count[s[right]] += 1 + if window_count[s[right]] == required_count.get(s[right], -1): + num_formed_count += 1 + + while num_formed_count == num_required_count: + if window_info.size > right - left + 1: + window_info.left = left + window_info.right = right + window_info.size = right - left + 1 + + window_count[s[left]] -= 1 + if window_count[s[left]] < required_count.get(s[left], -1): + num_formed_count -= 1 + left += 1 + + return ( + "" + if math.isinf(window_info.size) + else s[window_info.left : window_info.right + 1] + ) From bc0a8abe128a01ff898bc6ba02f02c8b52749908 Mon Sep 17 00:00:00 2001 From: tom4649 Date: Fri, 5 Jun 2026 06:43:54 +0900 Subject: [PATCH 2/4] Add step3_revised --- .../step3_revised.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 0076.Minimum-Window-Substring/step3_revised.py diff --git a/0076.Minimum-Window-Substring/step3_revised.py b/0076.Minimum-Window-Substring/step3_revised.py new file mode 100644 index 0000000..935b15d --- /dev/null +++ b/0076.Minimum-Window-Substring/step3_revised.py @@ -0,0 +1,42 @@ +import collections + + +class WindowInfo: + def __init__(self) -> None: + self.left: int | None = None + self.right: int | None = None + self.size: int | None = None + + def update(self, left, right): + self.left = left + self.right = right + self.size = right - left + 1 + + +class Solution: + def minWindow(self, s: str, t: str) -> str: + required_count = collections.Counter(t) + window_count = collections.defaultdict(int) + num_required_count = len(required_count) + window_info = WindowInfo() + + left = 0 + for right in range(len(s)): + window_count[s[right]] += 1 + if window_count[s[right]] == required_count.get(s[right], -1): + num_required_count -= 1 + + while num_required_count == 0: + if window_info.size is None or window_info.size > right - left + 1: + window_info.update(left, right) + + window_count[s[left]] -= 1 + if window_count[s[left]] < required_count.get(s[left], -1): + num_required_count += 1 + left += 1 + + return ( + "" + if window_info.size is None + else s[window_info.left : window_info.right + 1] + ) From 58f7e2783db0408529c0c552faaa91e169793f42 Mon Sep 17 00:00:00 2001 From: tom4649 Date: Fri, 5 Jun 2026 06:45:22 +0900 Subject: [PATCH 3/4] Fix --- 0076.Minimum-Window-Substring/step3_revised.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/0076.Minimum-Window-Substring/step3_revised.py b/0076.Minimum-Window-Substring/step3_revised.py index 935b15d..b5e7cc8 100644 --- a/0076.Minimum-Window-Substring/step3_revised.py +++ b/0076.Minimum-Window-Substring/step3_revised.py @@ -7,7 +7,7 @@ def __init__(self) -> None: self.right: int | None = None self.size: int | None = None - def update(self, left, right): + def update(self, left: int, right: int) -> None: self.left = left self.right = right self.size = right - left + 1 From f419c9e4ecf2c35a63840b91233eace51400a39d Mon Sep 17 00:00:00 2001 From: tom4649 Date: Sat, 6 Jun 2026 08:35:45 +0900 Subject: [PATCH 4/4] Add suggested chagnges --- 0076.Minimum-Window-Substring/step3_revised.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/0076.Minimum-Window-Substring/step3_revised.py b/0076.Minimum-Window-Substring/step3_revised.py index b5e7cc8..7435888 100644 --- a/0076.Minimum-Window-Substring/step3_revised.py +++ b/0076.Minimum-Window-Substring/step3_revised.py @@ -5,12 +5,16 @@ class WindowInfo: def __init__(self) -> None: self.left: int | None = None self.right: int | None = None - self.size: int | None = None def update(self, left: int, right: int) -> None: self.left = left self.right = right - self.size = right - left + 1 + + @property + def size(self) -> int | None: + if self.left is None or self.right is None: + return None + return self.right - self.left + 1 class Solution: