diff --git a/Python3/3. Longest Substring Without Repeating Characters.md b/Python3/3. Longest Substring Without Repeating Characters.md new file mode 100644 index 0000000..d8742cb --- /dev/null +++ b/Python3/3. Longest Substring Without Repeating Characters.md @@ -0,0 +1,113 @@ +## Step 1. Initial Solution + +- 文字列が与えられて重複しない部分文字列の最長長を調べる + - 文字列は英字, 数字, 記号, スペースもあり +- 前から見て行って重複しない間は長さを見る +- 重複したら重複以降を保持して続ける +- そんなに苦戦せずに書けた + +```python +class Solution: + def lengthOfLongestSubstring(self, s: str) -> int: + max_length = 0 + substring = "" + for char in s: + duplicate_place = substring.find(char) + if duplicate_place == -1: + substring += char + + substring_length = len(substring) + if substring_length > max_length: + max_length = substring_length + else: + substring = substring[duplicate_place + 1:] + char + return max_length +``` + +### Complexity Analysis + +- 時間計算量:O(N^2) +- 空間計算量:O(N) + +## Step 2. Alternatives + +- もう少し効率の良いやり方はありそう + - 各charの位置を辞書で保存すれば探す処理はO(1)で済むが更新に時間がかかる + - https://github.com/tokuhirat/LeetCode/pull/48/files#diff-59fd806da6e42daeb12a7afabcd326ca6953f65144e488ba169167138a8c2598R2-R4 + - 開始位置ごとに最後までiteration + - 中身は少し違うが計算量は同じ + - end_indexが動くのは少し分かりにくかった + - https://github.com/hayashi-ay/leetcode/pull/47/files#diff-eaf04e4839867b1c256a01b37e3fd908cd889582123148e5910d72e4e4fcb421R26 + - 確かに更新する必要はないか。現在地との差分を考えるこれでO(N)で計算できる + + ```python + class Solution: + def lengthOfLongestSubstring(self, s: str) -> int: + substring_start_position = -2 + max_length = 0 + char_to_position = defaultdict(lambda: -1) + for index, char in enumerate(s): + duplicate_position = char_to_position[char] + char_to_position[char] = index + if duplicate_position >= substring_start_position: + substring_start_position = duplicate_position + 1 + max_length = max(max_length, \ + index - substring_start_position + 1) + return max_length + ``` + + - https://github.com/olsen-blue/Arai60/pull/49/files#r2005295464 + - defaultdictを使わずにdict.get(x ,-1)としても良い + - この方が読んでいる側からすると脳内メモリを解放されて楽に読める + - setでも試す + + ```python + class Solution: + def lengthOfLongestSubstring(self, s: str) -> int: + chars_in_window = set() + left_index = 0 + max_length = 0 + for right_index, char in enumerate(s): + while char in chars_in_window: + chars_in_window.remove(s[left_index]) + left_index += 1 + chars_in_window.add(char) + length = right_index - left_index + 1 + max_length = max(max_length, length) + return max_length + ``` + + +## Step 3. Final Solution + +- setで書く方法が同時に覚えておく必要のある事が少ないので嬉しい + +```python +class Solution: + def lengthOfLongestSubstring(self, s: str) -> int: + max_length = 0 + substr_start = 0 + chars_in_substr = set() + for substr_end, char in enumerate(s): + while char in chars_in_substr: + chars_in_substr.remove(s[substr_start]) + substr_start += 1 + chars_in_substr.add(char) + max_length = max(max_length, substr_end - substr_start + 1) + return max_length +``` + +- string.findを使う方法も悪くはない + +```python +class Solution: + def lengthOfLongestSubstring(self, s: str) -> int: + max_length = 0 + substring_start = 0 + for substring_end, char in enumerate(s): + duplicate_position = s.find(char, substring_start, substring_end) + if duplicate_position != -1: + substring_start = duplicate_position + 1 + max_length = max(max_length, substring_end - substring_start + 1) + return max_length +```