部分和の数え上げで符号の付け方を数える

数の​並びの​それぞれに​ + か​ - を​付けて​足した​とき、​ちょうど​目標に​なる​付け方が​何通り​あるかを​数えます。​符号の​付け方の​問題を​「和が​ある​数に​なる​選び方の​数」に​言い​換え、​1 次元の​表で​数える​練習です。

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

問題

0 以上の整数の並び nums と、整数 target を受け取ります。nums のそれぞれの数の前に + か - のどちらかを付け、左から全部足します。足した結果がちょうど target になる符号の付け方が何通りあるかを返す関数を書いてください。

  • どの数にも、必ずどちらかの符号を 1 つ付けます。数の順番は変えません
  • 同じ値の数でも、位置が違えば別の数として数えます。0 に + を付けるのと - を付けるのも、別の付け方として数えます
  • nums の長さは 1 以上 20 以下、値はどれも 0 以上 1000 以下で、全部の合計は 1000 以下です
  • target は -1000 以上 1000 以下です

入力と出力の例

例 1

-2 -3 +5 と +2 +3 -5 の 2 通りです。

入力

nums = [2, 3, 5]
target = 0

出力

2

例 2

どちらかの 1 にだけ + を、どちらかの 2 にだけ + を付ければ 0 になります。2 × 2 で 4 通りです。

入力

nums = [1, 2, 1, 2]
target = 0

出力

4

例 3

4 と 6 にどう符号を付けても、結果は偶数です。奇数の 3 にはなりません。

入力

nums = [4, 6]
target = 3

出力

0

面接での聞かれ方

面接では、再帰で全部試す書き方を書いたあとに、速くする道を聞かれる流れが多いです。

  • 「各数に + か - を付けて、目標になる付け方の数を返してください」
  • 全部試す書き方を出すと「数が 20 個なら何通りですか? 100 個なら?」と、手間の増え方を聞かれます
  • 「+ を付けた数の合計だけで、答えが決まりませんか?」と、言い換えの手がかりを出されることもあります

0 が入るときに付け方を 2 通りと数えるかは、先に確かめておきます。この問題では 2 通りと数えます。

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

main.py
def sign_ways(nums, target):
    # ここに書きます
    pass


# 「実行」を押すと、この行の結果が出ます
print(sign_ways([2, 3, 5], 0))

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