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] + ) diff --git a/0076.Minimum-Window-Substring/step3_revised.py b/0076.Minimum-Window-Substring/step3_revised.py new file mode 100644 index 0000000..7435888 --- /dev/null +++ b/0076.Minimum-Window-Substring/step3_revised.py @@ -0,0 +1,46 @@ +import collections + + +class WindowInfo: + def __init__(self) -> None: + self.left: int | None = None + self.right: int | None = None + + def update(self, left: int, right: int) -> None: + self.left = left + self.right = right + + @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: + 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] + )