Skip to content

Conversation

@nittoco
Copy link
Owner

@nittoco nittoco commented Nov 17, 2024

URL: https://leetcode.com/problems/coin-change/description/
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.

Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

You may assume that you have an infinite number of each kind of coin.

num_coins, sum_val = stack.pop()
if sum_val > target_amount:
continue
if seen[sum_val] and num_coins > amount_to_needed_coin[sum_val]:
Copy link

@oda oda Nov 17, 2024

Choose a reason for hiding this comment

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

>=
これ、大違いで、{100, 101} の場合、100 + 101 + 100 も 101 + 100 + 100 も探索しますね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

か>=かよく考えずに書いてたら、大違いでした、、、
=だと、降順ソートされてない探索があったとしたら、降順ソートすれば同じamountの過去探索したものに絶対できるので矛盾で、降順ソートされたものしか探索されないですね。
実際TLEにならなかったです。

- dataclassでの実装
- BFSでの実装
- そもそもDPを、各配列の要素をnodeだと思った最短距離問題だと思っていたので、自分としては割と考えは自然だった
- これだと配るDPみたいになるのと、探索順序は違ってくる
Copy link

Choose a reason for hiding this comment

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

「配るDP」は、たぶん競技プログラミング同好会用語です。探したら秋葉拓哉のスライドが出てきました。
https://www.slideshare.net/slideshow/ss-3578511/3578511#58

Copy link

Choose a reason for hiding this comment

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

上がネットで見つかった最古の使用例です。

Copy link
Owner Author

Choose a reason for hiding this comment

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

Atcoder昔やってた時に解説で出てきて学んだのですが、ここから発祥なんですね

Copy link

Choose a reason for hiding this comment

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

「燃やす埋める」は、競技プログラミング同好会の時代には聞いたことがないですが2012年にはあったようですね。
https://web.archive.org/web/20150308235517/http://topcoder.g.hatena.ne.jp/CKomaki/

stack.append((num_coins + 1, sum_val + coin_val))
return self.NOT_EXIST
```
- 直して書いたやつTime Limit Exceeded、効率が悪い
Copy link

Choose a reason for hiding this comment

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

下の遅くなっている原因を >= に直したとすると、
このアルゴリズムは、coins の大きい方からグリーディーに作れる金額を列挙していることに相当します。
たとえば、[1000, 100, 10, 1] だったとすると、1000だけで作れる金額を列挙して、それに100を加えて作れる金額を列挙して、10も使える場合に作れる金額を列挙して、1も使えるとして作れる金額を列挙しています。
O(len(coins) * target) で抑えられていそうですね。


```python
class Solution(object):
def count_min_needed_coin_kind_so_far_to_make_amount(self, val_current_coin, min_needed_coin_for_amount, num_coin_kind, amount):
Copy link

Choose a reason for hiding this comment

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

1 行の長さが長すぎ、読みにくく感じました。適宜改行を入れることをおすすめいたします。

https://peps.python.org/pep-0008/#maximum-line-length

Limit all lines to a maximum of 79 characters.

https://google.github.io/styleguide/pyguide.html#s3.2-line-length

Maximum line length is 80 characters.


- このように1次元がシンプルだね
- min_needed_coin_for_amount[amount - coin_val]は変数定義しても良かったかも
- amount < coin_val よりcoin_val > amountが良かったかも

Choose a reason for hiding this comment

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

coin_val > amountに一票です。
通常はcoin_val <= amountという大小関係を想定していることが分かりやすいと思っています。

if min_needed_coin_for_amount[amount - coin_val] is None:
continue
if min_needed_coin_for_amount[amount] is None:
min_needed_coin_for_amount[amount] = min_needed_coin_for_amount[amount - coin_val] + 1

Choose a reason for hiding this comment

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

ここもcontinueでいいんじゃないでしょうか。

Copy link
Owner Author

Choose a reason for hiding this comment

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

多分これは意図したわけはなく書き忘れですね。ありがとうございます

- BFSでの実装
- そもそもDPを、各配列の要素をnodeだと思った最短距離問題だと思っていたので、自分としては割と考えは自然だった
- これだと配るDPみたいになるのと、探索順序は違ってくる
- dequeでやるのは同じdequeに色々なものが入って嫌なので、今の配列と次の配列で分けて実装

Choose a reason for hiding this comment

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

coin_countをdequeに入れて連れ回さなくていいのも良いですね。

Comment on lines +223 to +226
min_needed_coins = [None] * (target_amount + 1)
seen = [False] * (target_amount + 1)
min_needed_coins[0] = 0
seen[0] = True

Choose a reason for hiding this comment

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

min_needed_coins = [None] * (target_amount + 1)
min_needed_coins[0] = 0
seen = [False] * (target_amount + 1)
seen[0] = True

こちらの方が個人的には好みです。

Copy link
Owner Author

@nittoco nittoco Dec 30, 2024

Choose a reason for hiding this comment

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

この自分の書き方、2変数だからまだいいですけど、確かにもうちょっと増えると目の移動の距離が増えそうですね(という意図で合っていますか?)

Choose a reason for hiding this comment

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

min_needed_coins = [None] * (target_amount + 1)
min_needed_coins[0] = 0

この2つがセットで初期化のイメージがありました。

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.

5 participants