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

指定した値より大きい最大値を持つ部分配列の個数を求めるPythonプログラム

問題の概要

複数の整数が格納された配列があるとします。この配列から取り出せるすべての連続する部分配列(サブアレイ)を列挙し、それぞれの部分配列を「その中の最大要素」で置き換えます。さらに数値 k が与えられたとき、置き換え後の値が k より大きくなる部分配列が何個あるかを求めるのがこの問題です。

例えば、入力が input_array = [5, 6, 7, 8]k = 7 の場合、出力は 4 になります。

例を使った解説

入力配列 [5, 6, 7, 8] から取り出せる連続する部分配列は、次の10個です。

{5}, {6}, {7}, {8}, {5, 6}, {6, 7}, {7, 8}, {5, 6, 7}, {6, 7, 8}, {5, 6, 7, 8}

各部分配列をその中の最大要素で置き換えると、次のようになります。

{5}, {6}, {7}, {8}, {6}, {7}, {8}, {7}, {8}, {8}

このうち、値が 7 より大きいものは {8} が4回現れるため、4個となります。

解法のアプローチ:補集合の活用

すべての部分配列を実際に生成すると計算量が膨大になるため、ここでは「補集合」の考え方を使った効率的な手法を採用します。

長さ n の配列に含まれる連続する部分配列の総数は n × (n + 1) / 2 個です。そこで、

  • 全体の部分配列の数
  • 「すべての要素が k 以下である部分配列」の数

の差を取れば、「最大値が k より大きい部分配列」の個数が求まります。

具体的な手順

  • count := 0、consecutive := 0 で初期化する
  • input_array の各要素 x について以下を繰り返す
    • x > k の場合 → consecutive := 0(連続が途切れたためリセット)
    • それ以外の場合 → consecutive を1増やし、count に consecutive を加算する
  • 最後に「n × (n + 1) / 2 − count」を返す

ここで consecutive の累積加算により、k 以下の要素が m 個連続している区間では 1 + 2 + … + m = m × (m + 1) / 2 個の部分配列が自動的に数え上げられる仕組みです。

実装例

それでは、以下のPythonコードを見てみましょう。

def solve(input_array, k):
    count = 0
    consecutive = 0
    for x in input_array:
        if x > k:
            consecutive = 0
        else:
            consecutive += 1
            count += consecutive
    return len(input_array) * (len(input_array) + 1) // 2 - count

print(solve([5, 6, 7, 8], 7))

入力

[5, 6, 7, 8], 7

出力

4

まとめ

このアルゴリズムは配列を一度走査するだけで済むため、時間計算量は O(n)、空間計算量は O(1) と非常に効率的です。部分配列を全列挙する O(n²) 以上の素朴な方法と比べ、大きな入力に対しても高速に動作する点が大きなメリットです。

  1. Pythonで二分木の中から最大のBST(二分探索木)の合計値を見つけるプログラム

    問題の概要ある二分木が与えられたとします。この木の部分木の中に二分探索木(BST)が存在するかどうかを調べ、その中で最も大きなBSTを見つけ出し、そのノード値の合計を求めるのが目的です。合計値は、そのBSTに含まれる各ノードの値をすべて足し合わせたものになります。例えば、入力が次のような二分木だったとしましょう。この場合、出力は 12 となります。与えられた二分木の中に存在するBSTは次の部分木です。このBSTのノード値の合計 = 12 となります。解き方のアプローチこの問題を解くために、以下の手順で処理を進めます。変数 c := 0、m := null、value := 0 を初期化します。

  2. Pythonで倉庫(godown)に押し込めるボックスの数を求めるプログラム

    問題の概要 2つの整数配列が与えられていると仮定しましょう。一方のリストには単位幅のボックスの高さが、もう一方の配列には倉庫(godown)内の各部屋の高さが格納されています。部屋には 0〜n の番号が付いており、各部屋の高さは godown 配列の対応するインデックスに記録されています。ここで、倉庫に押し込むことのできるボックスの数を求めます。 ただし、以下のルールを守る必要があります。 ボックスを積み重ねることはできません。 ボックスの順序は自由に入れ替えられます。 ボックスは必ず左から右へ向かって挿入します。 もしボックスの高さがある部屋の高さより大きい場合、そのボックスおよびそれよ