-
Notifications
You must be signed in to change notification settings - Fork 0
Create 39. Combination Sum.md #52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| # 39. Combination Sum | ||
| ## STEP1 | ||
| - 何も見ずに解いてみる | ||
| - 78\. Subsets では各要素を使う使わないの2通りだったが、この問題は各要素を使えるだけ使って良い。 | ||
| ```python | ||
| class Solution: | ||
| def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: | ||
| results = [] | ||
|
|
||
| def generate_combination(index: int, combination: list[int]) -> None: | ||
| total = sum(combination) | ||
| if total == target: | ||
| results.append(combination) | ||
| return | ||
| if index == len(candidates): | ||
| return | ||
|
|
||
| generate_combination(index + 1, combination[:]) | ||
| num = candidates[index] | ||
| while total + num <= target: | ||
| combination = combination + [num] | ||
| total += num | ||
| generate_combination(index + 1, combination) | ||
|
|
||
| generate_combination(0, []) | ||
| return results | ||
| ``` | ||
| - generate_combination の引数 combination は毎回異なるオブジェクトを指すようにした。コピーしない場合は while:pop みたいなことをする必要があり煩雑になると思った。 | ||
| - generate_combination 内で if total > target: return を書くか迷った。 | ||
| - generate_combination の呼び出しをまとめようとすると以下になる。こちらの方がすこしわかりやすいかもしれない。 | ||
| ```python | ||
| next_combination = combination[:] | ||
| num = candidates[index] | ||
| while total <= target: | ||
| generate_combination(index + 1, next_combination) | ||
| next_combination = next_combination + [num] | ||
| total += num | ||
| ``` | ||
|
|
||
| - DP でも書いてみた。 | ||
| ```python | ||
| class Solution: | ||
| def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: | ||
| sum_to_combinations = [[] for _ in range(target + 1)] | ||
| sum_to_combinations[0].append([]) | ||
| for sum_ in range(target + 1): | ||
| if not sum_to_combinations[sum_]: | ||
| continue | ||
| for combination in sum_to_combinations[sum_]: | ||
| for num in candidates: | ||
| if combination and combination[-1] >= num: | ||
| continue | ||
| for i in range(1, (target - sum_) // num + 1): | ||
| sum_to_combinations[sum_ + num * i].append( | ||
| combination + [num] * i | ||
| ) | ||
| return sum_to_combinations[target] | ||
| ``` | ||
| - if not sum_to_combinations[sum_]:continue は不要でした。 | ||
|
|
||
| ## STEP2 | ||
| ### プルリクやドキュメントを参照 | ||
| - https://github.com/olsen-blue/Arai60/pull/53/files | ||
| - 解法1 が結構読みにくかった。traverse_candidates が index を進めない場合があることを最初読めていなくて、index == len(candidates) を先に確認したらダメなのではないかと考えてしまった。 | ||
| - シンプルに DP を実装している。 | ||
| - 一番外側で使える数字ごとにループを回すと、重複を考慮しないで済む。 | ||
| ```python | ||
| class Solution: | ||
| def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: | ||
| sum_to_combinations = [[] for _ in range(target + 1)] | ||
| sum_to_combinations[0].append([]) | ||
| for candidate in candidates: | ||
| for sum_ in range(candidate, target + 1): | ||
| for combination in sum_to_combinations[sum_ - candidate]: | ||
| sum_to_combinations[sum_].append(combination + [candidate]) | ||
| return sum_to_combinations[target] | ||
| ``` | ||
| - https://discord.com/channels/1084280443945353267/1235829049511903273/1265717341178822787 | ||
| - 分岐の分類。色々ありますね。 | ||
| - stack でも書いてみる。 | ||
| ```python | ||
| class Solution: | ||
| def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: | ||
| results = [] | ||
| combination_and_index = [([], 0)] | ||
|
|
||
| while combination_and_index: | ||
| combination, index = combination_and_index.pop() | ||
| if sum(combination) == target: | ||
| results.append(combination) | ||
| continue | ||
| if index >= len(candidates): | ||
| continue | ||
|
|
||
| num = candidates[index] | ||
| sum_ = sum(combination) | ||
| new_combination = combination[:] | ||
| while sum_ <= target: | ||
| combination_and_index.append((new_combination[:], index + 1)) | ||
| sum_ += num | ||
| new_combination.append(num) | ||
| return results | ||
| ``` | ||
| ## STEP3 | ||
| ### 3回ミスなく書く | ||
| ```python | ||
| class Solution: | ||
| def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: | ||
| results = [] | ||
|
|
||
| def generate_combination(index: int, combination: list[int]) -> None: | ||
| if sum(combination) == target: | ||
| results.append(combination) | ||
| return | ||
| if index >= len(candidates): | ||
| return | ||
|
|
||
| sum_ = sum(combination) | ||
| num = candidates[index] | ||
| new_combination = combination[:] | ||
| while sum_ <= target: | ||
| generate_combination(index + 1, new_combination[:]) | ||
| sum_ += num | ||
| new_combination.append(num) | ||
|
Comment on lines
+121
to
+124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 同じ index の数字が繰り返して使用される場合は同処理しているんだろう (index + 1 でしか再帰関数を呼ばないので) と少し考えてしまいました。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 考え方の違いで遷移の分類が色々あるところで面白いですね。 |
||
|
|
||
| generate_combination(0, []) | ||
| return results | ||
| ``` | ||
|
|
||
| 3分,3分,3分で3回Accept | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
合計値も再帰関数の引数にして引き回す書き方もできますね。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
以下のような感じですね。個人的には、実行時間が問題ないのであれば、重複した情報は省いてコードを簡潔にしたいので sum は各関数で計算するようにしていました。