Skip to content

322. Coin Change#37

Open
seal-azarashi wants to merge 8 commits intomainfrom
coin-change
Open

322. Coin Change#37
seal-azarashi wants to merge 8 commits intomainfrom
coin-change

Conversation

@seal-azarashi
Copy link
Owner

makeUpAmountToCoinCount[coinState.currentAmount()],
coinState.numCoins()
);

Copy link

Choose a reason for hiding this comment

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

ここの時点で更新がなされなかった場合、下の処理は不要ではないでしょうか。

たとえば、coins = {10, 11} だったとすると、1枚で作れるのは、10, 11 です。2枚で作れるのは、10 + 10, 10 + 11, 11 + 10, 11 + 11 がありますが、下の方の continue で、11 + 10 を弾いているつもりでしょうが、まだ 10 + 11 は Queue に入ったところなので、弾けていません。この後、3枚で作れる場合と考えていくと(コインの価格が十分に近いと Queue の中身は)、2^n で増えていきます。

Copy link
Owner Author

@seal-azarashi seal-azarashi Nov 6, 2024

Choose a reason for hiding this comment

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

ご指摘ありがとうございます。仰る通りで、修正したら DFS の実装よりも早くなりました。
修正内容は step 4 に記載しました。


### 非再帰の DFS

他の方の解法にあったので書いてみる。実行時間が上の解法より10倍以上長いが TLE にはならなかった。BFS の方が効率は良さそうに思えたが、テストケースとの相性がたまたまよかったのだろうか。
Copy link

Choose a reason for hiding this comment

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

DFS にしたことによって、結果的に上の問題が回避されています。coin の価格を降順に並べると少し速そうですね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

こちらも仰る通りでした。処理速度が6倍ぐらい早くなりました: fdad5c2

Copy link
Owner Author

Choose a reason for hiding this comment

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

再帰で実装してる方も15倍ぐらい早くなりますね: e63c235

@seal-azarashi seal-azarashi changed the title 322. Coin ChangeCoin change 322. Coin Change Nov 6, 2024
* ※ n = amount, m = coins.length
*/
class Solution {
private final int CANNOT_BE_MADE_UP = -1;
Copy link

Choose a reason for hiding this comment

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

  • private final int CANNOT_BE_MADE_UP = Integer.MAX_VALUE; とする。
  • minCoinCountToMakeUp をすべて CANNOT_BE_MADE_UP で Arrays.fill() しておく。
  • minCoinCountToMakeUp[0] = 0; としておく。

とすると、

for (int i = 1; i < minCoinCountToMakeUp.length; i++) {
    for (int coin : coins) {
    if (i - coin < 0 || minCoinCountToMakeUp[i - coin] == CANNOT_BE_MADE_UP) {
        continue;
    }
    minCoinCountToMakeUp[i] = Math.min(minCoinCountToMakeUp[i], minCoinCountToMakeUp[i - coin]
}

だけとなり、すこしシンプルになると思います。最後、minCoinCountToMakeUp[amount] が CANNOT_BE_MADE_UP 出ないことを確認する手間は増えます。

Copy link
Owner Author

Choose a reason for hiding this comment

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

確かにこちらの方が簡潔に思えました。step 4 に書いてみました: 3a99d93

* 各インデックスの数字と同じ数値の額を何枚のコインで作れるかを保持する。
* 計算の都合上、額が0の際は必要な枚数も0であるという情報が欲しいので、そのために要素数を + 1 している。
*/
int[] minCoinCountToMakeUp = new int[amount + 1];
Copy link

Choose a reason for hiding this comment

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

自分なら amountToMinCoins と付けると思いますが、好みの問題かもしれません。

Copy link
Owner Author

Choose a reason for hiding this comment

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

充分意味が通じるのなら短いに越したことはないので、より良い選択肢に思えました。step 4 に書いた別解では上記の名前にしています: 3a99d93

seal_azarashi added 2 commits November 8, 2024 07:21
Copy link

@hayashi-ay hayashi-ay left a comment

Choose a reason for hiding this comment

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

分量多くて全部は見れてないですが、見た部分で気になったところをコメントしました。

DFS、BFSの解法は、DPではなくて、グラフの問題として捉えて解いたという感じですかね。自分はこの方法で解いていないので参考になりました。最短経路探索と考えるとBFSの方が良いかもですね。

for (int coin : filteredCoins) {
int nextAmount = coinState.currentAmount() + coin;
if (nextAmount > amount) {
continue;

Choose a reason for hiding this comment

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

filteredCoinsが昇順に並んでいるので、一度nextAmountを超えたらそこでbreakしちゃって良いと思います。

public int coinChange(int[] coins, int amount) {
Objects.requireNonNull(coins, "Argument coins must not be null");

int[] filteredCoins = Arrays.stream(coins)

Choose a reason for hiding this comment

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

sortedのニュアンスも変数名にあっても良いかなとも思いました。あとはfilteredだけだと、どういう値が入っているかを想像しづらいかなと思いました。

.sorted()
.toArray();

int[] makeUpAmountToCoinCount = new int[amount + 1];

Choose a reason for hiding this comment

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

個人的は変数名が長いわりにどういう値が入っているかを想像するのが難しかったです。まあ英語力の問題とかもあるかもですが。


while (!coinStateStack.isEmpty()) {
CoinState coinState = coinStateStack.pop();
makeUpAmountToCoinCount[coinState.currentAmount()] = Math.min(

Choose a reason for hiding this comment

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

この更新タイミングは、スタックに詰めるときで良いと思うんですよね。わざわざスタックから取り出した後に遅らせる必要性がないように感じます。L500で途中で抜ける最適化も早めに値を書き換えて上げたほうが効果があるように思います。

あとその場合L484のあとにmakeUpAmountToCoinCount[0] = 0をしてあげる必要がありますね。

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