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

Pythonで「x以上の要素がちょうどx個」ある特別な配列のxを求めるプログラム

すべての要素が 0 または正の整数である配列 nums があるとします。この配列は、ある数値 x が存在して、nums の中に「x 以上の要素」がちょうど x 個含まれるとき、特別な配列(special array)と呼ばれます。ポイントは、x が必ずしも nums の要素である必要はないという点です。配列が特別な配列であればその x を求め、そうでなければ -1 を返します。

たとえば、入力が nums = [4, 6, 7, 7, 1, 0] の場合を考えてみましょう。4 以上の要素は 4, 6, 7, 7 の 4 個あるため、出力は 4 となります。

解き方のアプローチ

この問題は、次の手順で解くことができます。

  • i を 0 から nums の最大値まで 1 ずつ増やしながら調べる
  • 各 i について、nums 内の i 以上の要素の個数 count を数える
  • count が i と一致すれば、その i が答えなので返す
  • すべての候補を調べても見つからなければ -1 を返す

Pythonでの実装例

理解を深めるために、以下の実装を見てみましょう。

def solve(nums):
    for i in range(max(nums) + 1):
        count = 0
        for j in nums:
            if j >= i:
                count += 1
        if count == i:
            return i
    return -1

nums = [4, 6, 7, 7, 1, 0]
print(solve(nums))

入力

[4, 6, 7, 7, 1, 0]

出力

4

計算量の改善

上記の素朴な実装では、候補となる x の範囲(最大で max(nums) + 1 通り)ごとに配列全体を走査するため、時間計算量は O(n²) になります(n は配列の長さ)。配列をあらかじめ昇順にソートしておけば、二分探索(bisect モジュール)を使って「x 以上の要素の個数」を効率よく求められるため、計算量を O(n log n) まで抑えられます。

import bisect

def solve_fast(nums):
    nums.sort()
    n = len(nums)
    lo, hi = 0, n
    while lo <= hi:
        mid = (lo + hi) // 2
        cnt = n - bisect.bisect_left(nums, mid)
        if cnt == mid:
            return mid
        elif cnt > mid:
            lo = mid + 1
        else:
            hi = mid - 1
    return -1

nums = [4, 6, 7, 7, 1, 0]
print(solve_fast(nums))  # 出力: 4

このように、まずシンプルな全探索で問題の構造を理解し、その後ソートと二分探索を組み合わせることで、より大規模な入力にも対応できる実装へと改善できます。

  1. 【Python】配列の全要素を等しくするための最小移動回数を求めるアルゴリズム

    問題の概要 空でない整数型の配列が与えられたとき、すべての要素を等しい値に揃えるために必要な「最小の移動回数」を求める問題を考えてみましょう。ここでいう1回の移動とは、選択した要素を +1(増加) または -1(減少) させる操作のことです。 たとえば、配列が [1, 2, 3] の場合を考えます。このとき出力は 2 になります。理由は以下の通りです。 1 を 1 回増加させて 2 にする 3 を 1 回減少させて 2 にする 2 はそのまま 合計 2 回の移動ですべての要素を 2 に揃えられるため、答えは 2 となります。 解決のためのアプローチ この問題を効率的に解く鍵となるのが中央

  2. 【Python】配列の全要素の積をnで割った余りを求めるプログラムの書き方

    本記事では、以下の問題に対する解決策について詳しく解説します。問題文複数の数値からなる配列と整数 n が与えられたとき、配列内のすべての要素を掛け合わせた結果を n で割った余りを出力する必要があります。アプローチまず、arr[i] % n のように各要素の余りを個別に計算します。次に、その余りを現在の結果に掛け合わせます。掛け算を行うたびに再度剰余演算を適用することで、オーバーフローを回避できます。この手法は、モジュラー算術(合同式)の分配則に基づいています。( a * b) % c = ( ( a % c ) * ( b % c ) ) % c実装例def findremainder(ar