Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions arai60/combination-sum/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
めちゃくちゃざっくり考えると、全体で候補は40!
が、実際はそうはならない。でもかなり大きくなる気がする
でも結局全通りは計算しないと解けないので、メタ読みだけど全探索はできるだろう。やるとしても枝狩り程度
再帰とかでやることを考える。重複を含まないために、自分より大きいやつしか考えなくてよい

20m

メタ読みしてしまったのがよくないが、計算量の解析が難しい...
ざっくりした数で抑えて大丈夫なことを確認したい
何か良い方法あれば教えてください><
"""

class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
combination_candidate = []
combination_value_sum = 0
target_combinations = []
def count_target_combinations(index):
nonlocal combination_value_sum
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

step2 のように combination_value_sum を関数の引数として渡したほうがきれいに見えました。

また、変数名は sum_of_ の省略形の sum_ で始めるため、 sum_combination_values のほうが親善だと感じました。

for i in range(index, len(candidates)):
if combination_value_sum + candidates[i] > target:
continue
if combination_value_sum + candidates[i] == target:
target_combinations.append(list(combination_candidate) + [candidates[i]])
continue
combination_candidate.append(candidates[i])
combination_value_sum += candidates[i]
count_target_combinations(i)
combination_candidate.pop()
combination_value_sum -= candidates[i]
count_target_combinations(0)
return target_combinations

# stackでも書いてみる
# 実際再帰の深さによってどのようなデメリットがあるのかとかをちゃんと把握できていない気がする
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

再帰の深さは、 CPython 3.11.9 のデフォルトだと 1000 と設定されています。これを超えると例外が飛びます。

再帰の深さの上限は取得・設定できます。
https://docs.python.org/ja/3/library/sys.html#sys.getrecursionlimit
https://docs.python.org/ja/3/library/sys.html#sys.setrecursionlimit

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こういう場合って、メモリを食べちゃうからスタックで実装したほうが良いんですかね?
それとも、最近のコンピュータだとメモリはそこまで気にしなくてもよいんですかね
nodchipさんならどうしますか?

class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
target_combinations = []
combination_stack = [([], 0, 0)]
while combination_stack:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

変数名 "combination_stack"に関してですが、型名よりもcombination以外の値も入ってることを変数名に反映した方が良いのかなと思いました。3つ変数が入ると少し難しいですね。combination_sum_indexとかだとちょっと微妙ですね。良い案思いつかずすみません。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

コメントありがとうございます。
たしかに、自分もそう思います。
この場合、無理になにか表現せず、単にstackとかでもよいような気がしてきました
もしくは、current_comb_info_stackとかですかね

combination, value_sum, current_index = combination_stack.pop()
if value_sum == target:
target_combinations.append(combination)
continue
if value_sum > target:
continue

for i in range(current_index, len(candidates)):
combination_stack.append((combination + [candidates[i]], value_sum + candidates[i], i))
return target_combinations
25 changes: 25 additions & 0 deletions arai60/combination-sum/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
combination_value_sumは、引数にしたほうが良い
countじゃなくてgenerateのほうが適切→makeのほうが適切かも?
再帰する前に判定するよりも、再帰してからtargetに等しいかなどを判定したほうが、配列に追加済みなので簡単

combination_value_sum、ちょっと名前が冗長な気がしつつ、短縮するアイデアがない
再帰の深さにも注意。sys.setrecursionlimitとか
"""

class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
combination = []
target_combinations = []
def make_target_combinations(index, combination_value_sum):
if combination_value_sum == target:
target_combinations.append(list(combination))
return
if combination_value_sum > target:
return
for i in range(index, len(candidates)):
combination.append(candidates[i])
make_target_combinations(i, combination_value_sum + candidates[i])
combination.pop()
make_target_combinations(0, 0)
return target_combinations