From aa3217cbb5b8a19a9efcd00a7e60bfa7f5a529cb Mon Sep 17 00:00:00 2001 From: SuperHotDogCat Date: Tue, 7 May 2024 19:46:53 +0900 Subject: [PATCH 1/8] phase1 --- arai60/subsets/phase1.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 arai60/subsets/phase1.py diff --git a/arai60/subsets/phase1.py b/arai60/subsets/phase1.py new file mode 100644 index 0000000..d8887f5 --- /dev/null +++ b/arai60/subsets/phase1.py @@ -0,0 +1,13 @@ +class Solution: + def subsets(self, nums: List[int]) -> List[List[int]]: + all_subsets = [] + def recursive_find_all_subsets(subsets_so_far, index): + if subsets_so_far not in all_subsets: + all_subsets.append(subsets_so_far.copy()) + if nums[index] not in subsets_so_far: + recursive_find_all_subsets(subsets_so_far + [nums[index]], index) + index += 1 + if index < len(nums): + recursive_find_all_subsets(subsets_so_far, index) + recursive_find_all_subsets([], 0) + return all_subsets \ No newline at end of file From e9a963c39f5fd3fb49e64586d3a5b28241ee8492 Mon Sep 17 00:00:00 2001 From: SuperHotDogCat Date: Tue, 7 May 2024 22:44:03 +0900 Subject: [PATCH 2/8] phase1 --- .../remove_duplicates_from_sorted_list_2/phase1.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 arai60/remove_duplicates_from_sorted_list_2/phase1.py diff --git a/arai60/remove_duplicates_from_sorted_list_2/phase1.py b/arai60/remove_duplicates_from_sorted_list_2/phase1.py new file mode 100644 index 0000000..ae13d99 --- /dev/null +++ b/arai60/remove_duplicates_from_sorted_list_2/phase1.py @@ -0,0 +1,14 @@ +class Solution: + def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: + dummy_head = ListNode(0) + current_head = dummy_head + skip_number = None + while head: + if head.next and head.val != head.next.val and head.val != skip_number: + current_head.next = ListNode(head.val) + current_head = current_head.next + elif head.next == None and head.val != skip_number: + current_head.next = ListNode(head.val) + skip_number = head.val + head = head.next + return dummy_head.next \ No newline at end of file From d5663d65974bd1f4213587dc13c1d0bf3ee7c499 Mon Sep 17 00:00:00 2001 From: SuperHotDogCat Date: Tue, 28 May 2024 23:25:47 +0900 Subject: [PATCH 3/8] phase1 --- arai60/word_break/phase1.py | 56 +++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 arai60/word_break/phase1.py diff --git a/arai60/word_break/phase1.py b/arai60/word_break/phase1.py new file mode 100644 index 0000000..7d0904d --- /dev/null +++ b/arai60/word_break/phase1.py @@ -0,0 +1,56 @@ +# 配列を使ったdp +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + is_word_break = [False for _ in range(len(s))] + # is_word_break means s[:i+1] can be broken. + for i, c in enumerate(s): + string_from_beginning = s[:i+1] + for word in wordDict: + if string_from_beginning == word: + is_word_break[i] = True + elif i+1-len(word) >= 0 and s[i+1-len(word):i+1] == word and is_word_break[i-len(word)]: + is_word_break[i] = True + return is_word_break[len(s)-1] + +# 再起的なdp +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + is_word_break = [False for _ in range(len(s))] + seen = [False for _ in range(len(s))] + def recursiveWordBreak(index, seen, is_word_break): + if index >= len(s): + return + if seen[index]: + return + string_from_beginning = s[:index+1] + for word in wordDict: + if string_from_beginning == word: + seen[index] = True + is_word_break[index] = True + return recursiveWordBreak(index+1, seen, is_word_break) + elif index+1-len(word) >= 0 and word == s[index+1-len(word):index+1] and is_word_break[index-len(word)]: + seen[index] = True + is_word_break[index] = True + return recursiveWordBreak(index+1, seen, is_word_break) + seen[index] = True + return recursiveWordBreak(index+1, seen, is_word_break) + recursiveWordBreak(0, seen, is_word_break) + return is_word_break[len(s)-1] + +# タイムアウトしたコード, 本質的にはメモしてない再帰のように考える探索木が爆発してしまったと考えられる。 +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + char_to_string = defaultdict(list) + for string in wordDict: + char_to_string[string[0]].append(string) + stack = [0] + while stack: + cursor = stack.pop() + if cursor >= len(s): + return True + + beginning_char = s[cursor] + for string in char_to_string[beginning_char]: + if s[cursor:cursor+len(string)] in char_to_string[beginning_char]: + stack.append(cursor+len(string)) + return False \ No newline at end of file From 1ba9ee60192f3e83054b4055f5be4e2bec425c3f Mon Sep 17 00:00:00 2001 From: SuperHotDogCat Date: Tue, 28 May 2024 23:25:57 +0900 Subject: [PATCH 4/8] phase2 --- arai60/word_break/phase2.py | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 arai60/word_break/phase2.py diff --git a/arai60/word_break/phase2.py b/arai60/word_break/phase2.py new file mode 100644 index 0000000..adc3497 --- /dev/null +++ b/arai60/word_break/phase2.py @@ -0,0 +1,43 @@ +""" +Reference +shining-aiさん: https://github.com/shining-ai/leetcode/pull/39/files +自分も書いていてs[index+1-len(word):index+1]は時間計算量的にどうなのか気になった。ローリングハッシュで書き換えることを検討する。今回の問題はtop-downの方が書きやすかった...? +hayashi-ayさん: https://github.com/hayashi-ay/leetcode/pull/61/files +Exzrgさん: https://github.com/Exzrgs/LeetCode/pull/10/files startwithという方法もpythonにあることを学んだ。 + +結局最速はwordDict, sのローリングハッシュを計算してstoreしておくことになりそう。 +""" + +# @cacheで覚えておいて再帰 参考: shining-aiさん +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + @cache + def is_segmented(start): + if start == len(s): + return True + for word in wordDict: + if s[start:start+len(word)] != word: + continue + elif is_segmented(start+len(word)): + return True + return False + return is_segmented(0) + +# @cacheを使わずにメモ化 +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + seen = [False for _ in range(len(s))] + is_tokenized = [False for _ in range(len(s))] + def check_tokenizable(start, seen, is_tokenized): + if start == len(s): + return + if seen[start]: + return + seen[start] = True + for word in wordDict: + if s.startswith(word, start): + is_tokenized[start+len(word)-1] = True + check_tokenizable(start+len(word), seen, is_tokenized) + return + check_tokenizable(0, seen, is_tokenized) + return is_tokenized[-1] From c6ed2f8d66629998bb28a4fa952d4f2b788dc568 Mon Sep 17 00:00:00 2001 From: SuperHotDogCat Date: Tue, 28 May 2024 23:26:06 +0900 Subject: [PATCH 5/8] phase3 --- arai60/word_break/phase3.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 arai60/word_break/phase3.py diff --git a/arai60/word_break/phase3.py b/arai60/word_break/phase3.py new file mode 100644 index 0000000..2bc9327 --- /dev/null +++ b/arai60/word_break/phase3.py @@ -0,0 +1,17 @@ +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + seen = [False for _ in range(len(s))] + is_tokanizable = [False for _ in range(len(s))] + def check_tokanizable(start, seen, is_tokanizable): + if start >= len(s): + return + if seen[start]: + return + seen[start] = True + for word in wordDict: + if s.startswith(word, start): + is_tokanizable[start+len(word)-1] = True + check_tokanizable(start+len(word), seen, is_tokanizable) + return + check_tokanizable(0, seen, is_tokanizable) + return is_tokanizable[-1] \ No newline at end of file From 1c6a7c45edac67d069656de5b1e1e5d8c3f04110 Mon Sep 17 00:00:00 2001 From: SuperHotDogCat Date: Tue, 28 May 2024 23:28:01 +0900 Subject: [PATCH 6/8] remove unneccesary files --- .../remove_duplicates_from_sorted_list_2/phase1.py | 14 -------------- arai60/subsets/phase1.py | 13 ------------- 2 files changed, 27 deletions(-) delete mode 100644 arai60/remove_duplicates_from_sorted_list_2/phase1.py delete mode 100644 arai60/subsets/phase1.py diff --git a/arai60/remove_duplicates_from_sorted_list_2/phase1.py b/arai60/remove_duplicates_from_sorted_list_2/phase1.py deleted file mode 100644 index ae13d99..0000000 --- a/arai60/remove_duplicates_from_sorted_list_2/phase1.py +++ /dev/null @@ -1,14 +0,0 @@ -class Solution: - def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: - dummy_head = ListNode(0) - current_head = dummy_head - skip_number = None - while head: - if head.next and head.val != head.next.val and head.val != skip_number: - current_head.next = ListNode(head.val) - current_head = current_head.next - elif head.next == None and head.val != skip_number: - current_head.next = ListNode(head.val) - skip_number = head.val - head = head.next - return dummy_head.next \ No newline at end of file diff --git a/arai60/subsets/phase1.py b/arai60/subsets/phase1.py deleted file mode 100644 index d8887f5..0000000 --- a/arai60/subsets/phase1.py +++ /dev/null @@ -1,13 +0,0 @@ -class Solution: - def subsets(self, nums: List[int]) -> List[List[int]]: - all_subsets = [] - def recursive_find_all_subsets(subsets_so_far, index): - if subsets_so_far not in all_subsets: - all_subsets.append(subsets_so_far.copy()) - if nums[index] not in subsets_so_far: - recursive_find_all_subsets(subsets_so_far + [nums[index]], index) - index += 1 - if index < len(nums): - recursive_find_all_subsets(subsets_so_far, index) - recursive_find_all_subsets([], 0) - return all_subsets \ No newline at end of file From 975d2d8f9c2efb8fb0062385a2721e7f9fb707dd Mon Sep 17 00:00:00 2001 From: SuperHotDogCat Date: Tue, 28 May 2024 23:31:40 +0900 Subject: [PATCH 7/8] =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB?= =?UTF-8?q?=E6=9C=AB=E5=B0=BE=E3=81=AF=E6=94=B9=E8=A1=8C=E3=81=A7=E7=B5=82?= =?UTF-8?q?=E3=81=88=E3=82=8B(=E8=87=AA=E6=88=92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arai60/word_break/phase1.py | 2 +- arai60/word_break/phase3.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arai60/word_break/phase1.py b/arai60/word_break/phase1.py index 7d0904d..d16474f 100644 --- a/arai60/word_break/phase1.py +++ b/arai60/word_break/phase1.py @@ -53,4 +53,4 @@ def wordBreak(self, s: str, wordDict: List[str]) -> bool: for string in char_to_string[beginning_char]: if s[cursor:cursor+len(string)] in char_to_string[beginning_char]: stack.append(cursor+len(string)) - return False \ No newline at end of file + return False diff --git a/arai60/word_break/phase3.py b/arai60/word_break/phase3.py index 2bc9327..21de314 100644 --- a/arai60/word_break/phase3.py +++ b/arai60/word_break/phase3.py @@ -14,4 +14,4 @@ def check_tokanizable(start, seen, is_tokanizable): check_tokanizable(start+len(word), seen, is_tokanizable) return check_tokanizable(0, seen, is_tokanizable) - return is_tokanizable[-1] \ No newline at end of file + return is_tokanizable[-1] From c60e2e58672aaad1fab2bd30d5dee63de7d27c60 Mon Sep 17 00:00:00 2001 From: SuperHotDogCat Date: Wed, 29 May 2024 22:11:39 +0900 Subject: [PATCH 8/8] Modified --- arai60/word_break/phase4.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 arai60/word_break/phase4.py diff --git a/arai60/word_break/phase4.py b/arai60/word_break/phase4.py new file mode 100644 index 0000000..2d9ebd2 --- /dev/null +++ b/arai60/word_break/phase4.py @@ -0,0 +1,17 @@ +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + seen = [False] * len(s) + is_tokenizable = [False] * len(s) + def check_tokenizable(start): + if start >= len(s): + return + if seen[start]: + return + seen[start] = True + for word in wordDict: + if s.startswith(word, start): + is_tokenizable[start+len(word)-1] = True + check_tokenizable(start+len(word)) + return + check_tokenizable(0) + return is_tokenizable[-1] \ No newline at end of file