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

Pythonで配列の半分以上をゼロに還元できるかどうかを判定する方法

サイズ n の正整数からなるリストと、もうひとつの正整数 m が与えられたとします。ループの各反復において、配列内のいくつかの要素の値を 1 減らし、残りの要素の値を m 増やしていくことを考えます。何回かの反復の後、リストの要素のうち半分以上をゼロにできるかどうかを判定し、可能であれば True を、不可能であれば False を返すのが目的です。

たとえば、入力が input_list = [10, 18, 35, 5, 12]、m = 4 の場合、出力は True になります。

解法のポイント:剰余(mod)に着目する

この問題を効率的に解く鍵は、「m + 1 で割った余り」に注目することです。

ある要素 x に対して、全体 t 回の反復のうち d 回だけ「−1」を適用し、残りの t − d 回は「+m」が適用されるとすると、最終的な値は x − d + m × (t − d) と表せます。これが 0 になるには d × (m + 1) = x + m × t が必要で、変形すると t ≡ x (mod m + 1) という条件が導かれます。つまり、同じタイミングで同時にゼロにできる要素同士は、m + 1 で割った余りが互いに等しいということです。

したがって、「半分以上の要素をゼロに還元できる」ことは、「ある余りのグループにリスト全体の半分以上の要素が含まれている」ことと完全に一致します。

解法の手順

  1. サイズ m + 1 の頻度リスト(frequency_list)を 0 で初期化して作成します。
  2. 入力リストの各要素について input_list[i] mod (m + 1) を計算し、対応するインデックスのカウントを 1 増やします。
  3. 頻度リストを先頭から走査し、どれかのカウントがリストサイズの半分(n / 2)以上であれば、そこでループを抜けます。
  4. 条件を満たすカウントが見つかれば True を、最後まで見つからなければ False を返します。

実装例

以下に Python での実装例を示します。

def solve(input_list, m):
    frequency_list = [0] * (m + 1)
    i = 0
    while(i < len(input_list)):
        frequency_list[(input_list[i] % (m + 1))] += 1
        i += 1
    i = 0
    while(i <= m):
        if(frequency_list[i] >= (len(input_list)/ 2)):
            break
        i += 1
    if (i <= m):
        return True
    else:
        return False

input_list = [10, 18, 35, 5, 12]
print(solve(input_list, 4))

入力

[10, 18, 35, 5, 12], 4

出力

True

動作の解説

入力例では、各要素を m + 1 = 5 で割った余りは次のようになります。

  • 10 % 5 = 0
  • 18 % 5 = 3
  • 35 % 5 = 0
  • 5 % 5 = 0
  • 12 % 5 = 2

その結果、frequency_list は [3, 0, 1, 1, 0] となり、余り 0 のグループに 3 個の要素が含まれています。リストサイズ 5 の半分は 2.5 なので、3 ≥ 2.5 という条件を満たし、True が返されます。

計算量

  • 時間計算量:O(n + m)(各要素の余り計算に O(n)、頻度リストの走査に O(m))
  • 空間計算量:O(m)(頻度リストの分)

補足

Python 3 では len(input_list) / 2 は浮動小数点数を返しますが、整数との比較は問題なく動作します。より明示的にしたい場合は、math.ceil(len(input_list) / 2) や (len(input_list) + 1) // 2 を使う方法もあります。

  1. Pythonでソート済み配列内の数値が過半数要素(マジョリティ要素)かどうかを判定する方法

    問題概要 非降順(昇順)にソートされた整数配列 nums と、ある数値 target が与えられます。この target が「過半数要素(マジョリティ要素)」であるかどうかを判定してください。ここで、長さ N の配列における過半数要素とは、配列内に N/2 回より多く出現する要素のことを指します。 例えば、配列が [2,4,5,5,5,5,5,6,6] で target が 5 の場合を考えてみましょう。配列の長さは 9 なので、9/2 = 4.5 より多く出現すれば過半数要素です。実際、5 は 5 回出現しているため条件を満たし、出力は true になります。 解法のアプローチ:二分探索の

  2. Pythonで配列が単調(モノトニック)かどうかを判定する方法

    この記事では、与えられた配列が「単調(モノトニック)」であるかどうかを判定するための考え方と実装方法について解説します。 問題の定義 n個の整数を含む配列 Arr が入力として与えられます。このとき、その配列が単調な性質を持っているかどうかを判定する必要があります。 配列が単調であるとは、要素が最初から最後まで連続して増加しているか、または連続して減少している状態を指します。つまり、増加と減少が混在していない配列が単調な配列です。 数学的な定義 配列 A が単調増加であるのは、すべての i <= j に対して次の条件が成り立つ場合です。 A[i] <= A[j] 同様に、配列 A