動的計画法で硬貨の組み合わせが何通りあるかを数える

何種類かの​硬貨を​何枚でも​使える​とき、​ちょうど​ある​金額に​なる​組み合わせが​何通り​あるかを​数えます。​並べる​順の​違いを​数えないために、​硬貨の​繰り返しを​外側に​置く​理由まで​つかむ練習です。

海外で定番の問題リスト 4 本のうち 1 本に入っています (NeetCode 150)

問題

硬貨の額面の並び coins と、金額 amount を受け取ります。どの硬貨も何枚でも使えるとき、合計がちょうど amount になる硬貨の組み合わせが何通りあるかを返す関数を書いてください。

  • 組み合わせは、どの硬貨を何枚使うかだけで区別します。出す順番の違いは同じ 1 通りです。たとえば 2 円、3 円の順と 3 円、2 円の順は同じです
  • amount が 0 のときは、硬貨を 1 枚も使わない 1 通りがあるので 1 を返します。作れないときは 0 を返します
  • coins の長さは 1 以上 300 以下で、額面はどれも違います。額面は 1 以上 5000 以下です
  • amount は 0 以上 5000 以下です。答えは 2147483647 以下に収まるものとします

入力と出力の例

例 1

10 円 1 枚と 1 円 2 枚、5 円 2 枚と 1 円 2 枚、5 円 1 枚と 1 円 7 枚、1 円 12 枚の 4 通りです。

入力

coins = [1, 5, 10]
amount = 12

出力

4

例 2

2 円 2 枚と 3 円 1 枚の 1 通りだけです。出す順番で数えると 2、2、3 と 2、3、2 と 3、2、2 の 3 通りになりますが、ここでは 1 通りと数えます。

入力

coins = [2, 3]
amount = 7

出力

1

例 3

金額が 0 なら、何も出さない 1 通りです。

入力

coins = [4]
amount = 0

出力

1

面接での聞かれ方

面接では、最少の枚数を求めるおつりの問題を解いたあとに、続きとして出されることが多いです。

  • 「では、ちょうどその金額にする組み合わせは何通りありますか?」
  • 書いた答えが大きすぎると、「2 と 3 で 5 を作るのは何通りですか?」と小さな例で確かめさせられます。順番違いを別に数えていないかを見ています
  • 「2 重の繰り返しの内と外を入れ替えると、何を数えることになりますか?」と、繰り返しの順の意味を聞かれます

最少の枚数の問題と表の形は似ていますが、表の欄の意味と、繰り返しの順が大事になります。順番を区別するかどうかを、最初に確かめておきます。

アルゴリズムのチートシートの「動的計画法 (DP)」に、​この​型の​要点を​表と​コードで​まとめています。

main.py
def coin_ways(coins, amount):
    # ここに書きます
    pass


# 「実行」を押すと、この行の結果が出ます
print(coin_ways([1, 5, 10], 12))

できているか「例で確かめる」を押すと、問題の例を全部この関数に渡して、通ったかをここに出します