Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonで合計がターゲットに一致する重複しない2つの部分配列を見つけるプログラム

問題の概要

配列 arr と整数 target が与えられたとします。ここで、arr の中から互いに重なり合わない2つの部分配列を見つけ、それぞれの要素の合計が target と一致するようにします。条件を満たす組み合わせが複数存在する場合は、2つの部分配列の長さの合計が最小になるものを選択します。求める答えはその長さの合計の最小値であり、該当する部分配列が存在しない場合は -1 を返します。

例として、入力が arr = [5,2,6,3,2,5]target = 5 の場合を考えてみましょう。合計が 5 になる部分配列には [5][3,2][5] の3つがあります。この中から重ならない2つを選び、長さの合計を最小にすると、長さ1の [5][5] の組み合わせが最適となり、答えは 2 になります。

アルゴリズムのアプローチ

この問題は、累積和(プレフィックスサム)ハッシュマップを組み合わせることで効率的に解けます。「あるインデックスまでに見つかった target に一致する部分配列の最短の長さ」を記録しておくことで、現在の部分配列と重ならない過去の候補を素早く参照できるのがポイントです。

  • ans := 無限大(答えの初期値)

  • best := arr と同じサイズの配列を作り、すべて無限大で初期化する

  • prefix := 0(累積和)

  • latest := キー 0 に対して -1 を格納したマップ

  • arr の各インデックス i と値 x について以下を実行する

    • prefix := prefix + x

    • (prefix - target)latest に存在する場合

      • ii := latest[prefix - target]

      • ii >= 0 であれば

        • ans := ans(i - ii + best[ii]) の最小値

      • best[i] := i - ii

    • i が 0 以外の場合

      • latest[prefix] := i

  • ans < 999999 であれば ans を返し、それ以外は -1 を返す

実装例

以下のPythonコードで実際の動作を確認できます。

def solve(arr, target):
   ans = 999999
   best = [999999]*len(arr)
   prefix = 0
   latest = {0: -1}
   for i, x in enumerate(arr):
      prefix += x
      if prefix - target in latest:
         ii = latest[prefix - target]
         if ii >= 0:
            ans = min(ans, i - ii + best[ii])
         best[i] = i - ii
      if i: best[i] = min(best[i-1], best[i])
      latest[prefix] = i
   return ans if ans < 999999 else -1

arr = [5,2,6,3,2,5]
target = 5
print(solve(arr, target))

入力

[5,2,6,3,2,5], 5

出力

2

コードのポイント

このアルゴリズムの計算量は O(n) です。latest マップは「ある累積和が最後に現れたインデックス」を記録し、best 配列は「インデックス i までに見つかった target に一致する部分配列の最短の長さ」を保持します。これにより、現在見つけた部分配列の終端 i と、それより前に終わる別の部分配列を組み合わせた場合の総長を即座に評価でき、配列を一度走査するだけで答えを求められます。

  1. Pythonで最大の成功確率を持つパスを見つけるプログラムの実装方法

    問題の概要 n 個のノード(ノードには 0 から順に番号が振られています)からなる無向重み付きグラフを考えます。このグラフは辺リスト(edge list)として入力され、各辺 e には「その辺を通過する際の成功確率」probability[e] が割り当てられています。さらに、開始ノード(start)と終了ノード(end)も与えられます。 求めたいのは、start から end へ移動するときに成功確率が最大となる経路であり、答えとしてその成功確率を返します。経路がひとつも存在しない場合は 0 を返してください。 たとえば、次のような入力が与えられたとします。 この場合の出力は 0.25

  2. Pythonで解く「Two Sum(2つの合計)」問題:ハッシュマップを使った効率的な実装方法

    整数の配列が与えられたとき、その中から2つの要素を選び、その合計が指定されたターゲット値と一致するようなインデックスのペアを返す問題を考えてみましょう。これは、アルゴリズム学習やコーディング面接で非常によく知られている「Two Sum(2つの合計)」問題です。ここでは、配列内に必ず一意な解が1つだけ存在するという前提を置きます。つまり、同じターゲットに対して複数のインデックスの組み合わせが存在することはありません。問題の例例として、配列 A = [2, 8, 12, 15]、ターゲットの合計値が 20 である場合を考えます。このとき A[1] + A[2] = 8 + 12 = 20 となるた