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

Pythonで配列を合計が等しいk個の連続する部分配列に分割できるか判定する方法

数値の配列 nums と整数 k が与えられたとき、numsk個の連続する部分配列に分割して、それぞれの部分配列の要素の合計がすべて等しくなるようにできるかどうかを判定する問題を考えてみましょう。

問題の例

たとえば、入力が nums = [2, 5, 3, 4, 7]k = 3 の場合を考えます。このとき、[(2, 5), (3, 4), (7)] のように3つに分割でき、各部分配列の合計はいずれも 7 で等しくなるため、出力は True になります。

解法のアプローチ

この問題は累積和(prefix sum)を使うことで効率的に解けます。全体の合計が k で割り切れない場合は即座に False を返せばよく、割り切れる場合は累積和を走査しながら、目標となる合計(全体の合計 ÷ k)に達する位置を順番に記録していきます。

具体的には、以下の手順で処理を行います。

  1. nnums のサイズとします。
  2. cumul_sum として nums の全要素の累積和を計算します。
  3. total_sumcumul_sum[n - 1](配列全体の合計)とします。
  4. total_sumk で割り切れない場合は False を返します。
  5. count = 0pos = -1 として初期化します。
  6. i を 0 から n-1 までループします。
    • pos が -1 のときは sub = 0、それ以外のときは sub = cumul_sum[pos] とします。
    • cumul_sum[i] - subtotal_sum / k と等しければ、その位置で区切りが確定したことになるので、pos = i として count を1増やします。
    • そうでなく、cumul_sum[i] - cumul_sum[pos]total_sum / k を超えた場合は、それ以降に有効な区切りが存在しないためループを抜けます。
  7. 最後に、countk と等しければ True、そうでなければ False を返します。

実装例

以下はPythonでの実装例です。

def solve(nums, k):
   n = len(nums)
   cumul_sum = [0 for i in range(n)]
   cumul_sum[0] = nums[0]
   for i in range(1, n):
       cumul_sum[i] = cumul_sum[i - 1] + nums[i]
   total_sum = cumul_sum[n - 1]
   if total_sum % k != 0:
       return False
   count = 0
   pos = -1
   for i in range(n):
       if pos == -1:
           sub = 0
       else:
           sub = cumul_sum[pos]
       if cumul_sum[i] - sub == total_sum / k:
           pos = i
           count += 1
       elif cumul_sum[i] - cumul_sum[pos] > total_sum / k:
           break
   return count == k

nums = [2, 5, 3, 4, 7]
k = 3
print(solve(nums, k))

入力

[2, 5, 3, 4, 7], 3

出力

True

計算量と補足

このアルゴリズムの時間計算量は O(n)、空間計算量も累積和の保存に O(n) 必要となります。配列を一度走査するだけで判定できるため、非常に効率的です。

なお、Pythonでは / 演算子は浮動小数点除算を行うため、厳密な整数比較が必要な場合は //(整数除算)を使用するとより安全です。また、この方法は「連続する部分配列」への分割のみを扱う点に注意してください。要素を並べ替えてよい場合は、貪欲法やバックトラッキングなど別のアプローチが必要になります。

  1. PythonのBST(二分探索木)に指定した合計になるトリプレットが存在するか判定する方法

    問題概要 整数値を持つ二分探索木(BST)と、ある数値「total」が与えられたとします。このとき、BSTの中から3つの要素を選び、その合計が「total」と一致するような組み合わせ(トリプレット)が存在するかどうかを判定するのが、本記事のテーマです。 例えば、次のようなBSTが入力として与えられた場合を考えてみます。 total = 12 の場合、出力は True になります。 解法のアプローチ この問題は、BSTを中順走査(inorder traversal)するとノードの値が昇順に並ぶという性質を利用することで、効率的に解くことができます。全体の流れは以下の通りです。 結果を格納する

  2. Pythonで配列を合計が等しい3つの部分に分割する方法

    問題の概要整数の配列 A が与えられたとき、その配列を合計が等しい3つの空でない部分に分割できる場合にのみ true を返す問題を考えます。形式的には、i + 1 < j を満たすインデックス i, j が存在し、次の3つの区間の合計がすべて等しくなるとき、配列は分割可能とみなせます。第1部分:A[0] + A[1] + ... + A[i]第2部分:A[i+1] + A[i+2] + ... + A[j-1]第3部分:A[j] + A[j+1] + ... + A[len(A)-1]たとえば、入力が [0,2,1,-6,6,-7,9,1,2,0,1] の場合、出力は true になりま