diff --git a/arai60/combination_sum/phase1.py b/arai60/combination_sum/phase1.py new file mode 100644 index 0000000..92ed9b2 --- /dev/null +++ b/arai60/combination_sum/phase1.py @@ -0,0 +1,30 @@ +from typing import List + +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + # 再帰でも解けそうな気がするが, ひとまず単純な探索で解く + + stack = [[[], 0, target]] # [current_combination, current_candidate_index, current_target] + combinations = [] + while stack: + current_combination, current_candidate_index, current_target = stack.pop() + + if current_target == 0 and current_combination not in combinations: + combinations.append(current_combination) + continue + + if current_target - candidates[current_candidate_index] >= 0: + tmp_current_combination = current_combination.copy() # copy + tmp_current_combination.append(candidates[current_candidate_index]) + stack.append([tmp_current_combination, current_candidate_index, current_target - candidates[current_candidate_index]]) + + if current_candidate_index + 1 < len(candidates) and current_target - candidates[current_candidate_index+1] >= 0: + tmp_current_combination = current_combination.copy() # copy + tmp_current_combination.append(candidates[current_candidate_index+1]) + stack.append([tmp_current_combination, current_candidate_index+1, current_target - candidates[current_candidate_index+1]]) + + if current_candidate_index + 1 < len(candidates): + tmp_current_combination = current_combination.copy() # copy + stack.append([tmp_current_combination, current_candidate_index+1, current_target]) + + return combinations \ No newline at end of file diff --git a/arai60/combination_sum/phase2.py b/arai60/combination_sum/phase2.py new file mode 100644 index 0000000..fa7b0dd --- /dev/null +++ b/arai60/combination_sum/phase2.py @@ -0,0 +1,66 @@ +""" +Reference +hayashi-ay: https://github.com/hayashi-ay/leetcode/pull/65/files +shining-ai: https://github.com/shining-ai/leetcode/pull/52/files +phase1の方法だと重複する場合が出てきた分だけ状態数も増えていることに気づいた。 +indexを増やすか今のindexが指す値を足すかで場合分けすれば十分であることがわかった。 +あと現在の足し込んだ値がtargetより大きいかで判断した方が多分素直な実装ですね(phase1でcurrent_target - candidates[current_candidate_index] >= 0と書いていた) + +あとは, +make_combination(index + 1, current_sum) +partial_combination.append(candidates[index]) +make_combination(index, current_sum + candidates[index]) +partial_combination.pop() +のような再帰を考えたことはなかったですね, これで再帰関数の引数から現在のcombinationを入れなくて済むんですね + +Mike0121: https://github.com/Mike0121/LeetCode/pull/1/files +時間計算量が分割数というらしい +""" + +# 再帰, whileの2通りで書く +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + combinations = [] + stack = [[[], 0, 0]] # current_combination, current_index, current_value + while stack: + current_combination, current_index, current_value = stack.pop() + if current_value == target: + combinations.append(current_combination) + continue + + if current_value > target: + continue + + if current_index >= len(candidates): + continue + + stack.append([current_combination, current_index + 1, current_value]) + added_current_combination = current_combination.copy() + added_current_combination.append(candidates[current_index]) + stack.append([added_current_combination, current_index, current_value + candidates[current_index]]) + + return combinations + +# 再帰 +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + combinations = [] + partial_combination = [] + def make_combinations(index: int, total: int) -> None: + if total == target: + combinations.append(partial_combination.copy()) + return + + if total > target: + return + + if index >= len(candidates): + return + + make_combinations(index + 1, total) + partial_combination.append(candidates[index]) + make_combinations(index, total + candidates[index]) + partial_combination.pop() + + make_combinations(0, 0) + return combinations \ No newline at end of file diff --git a/arai60/combination_sum/phase3.py b/arai60/combination_sum/phase3.py new file mode 100644 index 0000000..7dd255a --- /dev/null +++ b/arai60/combination_sum/phase3.py @@ -0,0 +1,23 @@ +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + # 書くのが安定しているwhileで書く + combinations = [] + stack = [[[], 0, 0]] # current_combination, current_index, current_value + while stack: + current_combination, current_index, current_value = stack.pop() + if current_value == target: + combinations.append(current_combination) + continue + + if current_value > target: + continue + + if current_index >= len(candidates): + continue + + stack.append([current_combination, current_index + 1, current_value]) + added_current_combination = current_combination.copy() + added_current_combination.append(candidates[current_index]) + stack.append([added_current_combination, current_index, current_value + candidates[current_index]]) + + return combinations \ No newline at end of file diff --git a/arai60/combination_sum/phase4.py b/arai60/combination_sum/phase4.py new file mode 100644 index 0000000..51224f4 --- /dev/null +++ b/arai60/combination_sum/phase4.py @@ -0,0 +1,20 @@ +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + combinations_of_sum_equals_target: List[List[int]] = [] # You will get the value of the target when all the elements of combinations are added together. + stack = [([], 0, 0)] + while stack: + combinations_so_far, index_to_append, sum_so_far = stack.pop() + # sum(combinations_so_far) == sum_so_far + if sum_so_far == target: + combinations_of_sum_equals_target.append(combinations_so_far) + continue + if sum_so_far > target: + continue + if index_to_append >= len(candidates): + continue + + stack.append((combinations_so_far, index_to_append + 1, sum_so_far)) + append_value = candidates[index_to_append] + stack.append((combinations_so_far + [append_value], index_to_append, sum_so_far + append_value)) + + return combinations_of_sum_equals_target \ No newline at end of file