Skip to content

39. Combination Sum #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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

39. Combination Sum #52

wants to merge 1 commit into from

Conversation

fhiyo
Copy link
Owner

@fhiyo fhiyo commented Jul 24, 2024

Copy link

@thonda28 thonda28 left a comment

Choose a reason for hiding this comment

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

DP を使って解くこともできると思うので、そちらでも実装してみるといいかもです。


## 3rd

自分的にはyieldで書くのが分かりやすい...この問題では返り値がlistだから旨味はないが、lazyに計算できるのでメモリ効率も本来なら良いし。

Choose a reason for hiding this comment

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

個人的には yield が使われているコードは理解しにくいと感じました(僕が yield を書くのも読むのも慣れていないからかもですが)

@fhiyo
Copy link
Owner Author

fhiyo commented Jul 24, 2024

DP を使って解くこともできると思うので、そちらでも実装してみるといいかもです。

ありがとうございます、DPは全く思いついてなかったです。実装してみました。

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        sum_combinations = [[] for _ in range(target + 1)] # sum_combinations[i]: combinations whose sum is equal to i
        for candidate in candidates:
            if candidate > target:
                continue
            sum_combinations[candidate].append([candidate])
            for i in range(candidate + 1, target + 1):
                for combination in sum_combinations[i - candidate]:
                    sum_combinations[i].append(combination + [candidate])
        return sum_combinations[target]

@thonda28
Copy link

DP を使って解くこともできると思うので、そちらでも実装してみるといいかもです。

ありがとうございます、DPは全く思いついてなかったです。実装してみました。

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        sum_combinations = [[] for _ in range(target + 1)] # sum_combinations[i]: combinations whose sum is equal to i
        for candidate in candidates:
            if candidate > target:
                continue
            sum_combinations[candidate].append([candidate])
            for i in range(candidate + 1, target + 1):
                for combination in sum_combinations[i - candidate]:
                    sum_combinations[i].append(combination + [candidate])
        return sum_combinations[target]

よさそうです。個人的にはこちらの解法が理解も実装も簡単だと感じました。(簡単なら良いというわけではないですが)

初期値として sum_combinations[0].append([]) としておくと、よりシンプルなコードにできそうです。

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        sum_combinations = [[] for _ in range(target + 1)] # sum_combinations[i]: combinations whose sum is equal to i
        sum_combinations[0].append([])
        for candidate in candidates:
            for i in range(candidate, target + 1):
                for combination in sum_combinations[i - candidate]:
                    sum_combinations[i].append(combination + [candidate])
        return sum_combinations[target]

@fhiyo
Copy link
Owner Author

fhiyo commented Jul 24, 2024

なるほど sum([]) が 0だから初期値としても分かりやすいですね。参考になります 🙏

- https://github.com/shining-ai/leetcode/pull/52
- https://discord.com/channels/1084280443945353267/1200089668901937312/1222146483751485440
- https://github.com/hayashi-ay/leetcode/pull/65

Copy link

Choose a reason for hiding this comment

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

この問題ですが、基本的にはバックトラックをするわけですが、
分類してみると、いくつかあるように思います。

[A, A] まで使うことが確定していて B 以降しか使ってはいけないという状況下で、

  1. B を一つ使うか、C 以降しか使ってはいけないか、に分岐する。
  2. B の使う数を列挙して分岐し、C 以降しか使ってはいけないに遷移する。
  3. 次の1個が、B, C, D, E, F... である場合に分岐する。

あたりのように思っています。
とにかく、抜け漏れなく分類ができれば、いいということでしょうか。

Copy link
Owner Author

Choose a reason for hiding this comment

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

2番は他の方の実装を見てもあまりピンとこなくて自分では書かなかったんですが、上のように言語化するとBの使う数を0個以上b個以下 (今まで使った数と合わせて合計がtarget以下となる個数の最大がb) の範囲で分岐してC以降しか使わないようにする、と考えることができますね。そう考えると自然な発想だなと感じました


def make_combinations(combination: list[int], total: int, start: int):
for i in range(start, len(candidates)):
if total + candidates[i] > target:

Choose a reason for hiding this comment

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

total + candidates[i]を、変数にしても良いかと思いました。

Copy link
Owner Author

Choose a reason for hiding this comment

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

いい名前を思いつかなかったのでそのまま書いたんですよね...new_totalしか思いつかず。それでも変数にすれば良かったんですが。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants