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

【C++】ソート済み配列から目標値に最も近い要素を検索する方法

n個の要素を持つソート済み配列Aがあるとします。この中から、指定された整数に最も近い値を見つけたいと思います。配列には重複した値や負の数が含まれている場合もあります。

例えば、配列が [2, 5, 6, 7, 8, 8, 9] で目標値が 4 の場合、最も近い要素は 5 となります。

解決のアプローチ

配列を先頭から順に走査し、各要素と目標値の絶対差を記録しておき、最後に差が最小となる要素を返すという線形探索の方法もあります。しかし、配列がすでにソートされているため、二分探索(バイナリサーチ)を使えば O(log n) の時間計算量でより効率的に解くことができます。

二分探索を用いた手順は以下の通りです。

  • 目標値が先頭要素以下であれば、先頭要素をそのまま返す
  • 目標値が末尾要素以上であれば、末尾要素をそのまま返す
  • それ以外の場合は二分探索を行い、目標値が隣接する2つの要素の間に位置するとき、どちらの要素がより近いかを判定して返す

C++による実装例

#include<iostream>
#include<list>
using namespace std;

// 隣接する2つの値のうち、目標値に近い方を返す補助関数
int getNearest(int x, int y, int target) {
    if (target - x >= y - target)
        return y;
    else
        return x;
}

// 二分探索で最も近い要素を求める関数
int getNearestElement(int arr[], int n, int target) {
    if (target <= arr[0])
        return arr[0];
    if (target >= arr[n - 1])
        return arr[n - 1];

    int left = 0, right = n, mid = 0;
    while (left < right) {
        mid = (left + right) / 2;
        if (arr[mid] == target)
            return arr[mid];
        if (target < arr[mid]) {
            // 目標値が arr[mid-1] と arr[mid] の間にある場合
            if (mid > 0 && target > arr[mid - 1])
                return getNearest(arr[mid - 1], arr[mid], target);
            right = mid;
        } else {
            // 目標値が arr[mid] と arr[mid+1] の間にある場合
            if (mid < n - 1 && target < arr[mid + 1])
                return getNearest(arr[mid], arr[mid + 1], target);
            left = mid + 1;
        }
    }
    return arr[mid];
}

int main() {
    int arr[] = { 2, 5, 6, 7, 8, 8, 9 };
    int n = sizeof(arr) / sizeof(arr[0]);
    int target = 4;
    cout << "Nearest element of " << target << " is: " << getNearestElement(arr, n, target);
}

実行結果

Nearest element of 4 is: 5

このコードでは、まず目標値が配列の範囲外にないかを確認し、範囲内であれば二分探索によって候補を絞り込みます。目標値が2つの隣接要素の間に挟まれた時点で、補助関数 getNearest を使って距離が近い方の値を返す仕組みです。これにより、重複や負の数が含まれる配列でも正確に最も近い要素を高速に取得できます。

  1. C++で配列内の各要素に最も近い大きい値を効率的に検索する方法

    この記事では、配列内の各要素に対して「最も近い大きい値」を効率的に検索する方法を解説します。ある要素 x より大きい値が配列内に存在する場合、その中で最も小さい値(次に大きい要素)をその要素の答えとし、存在しない場合は -1 を出力します。例として、配列が {10, 5, 11, 10, 20, 12} の場合、結果は {11, 10, 12, 11, -1, 20} となります。最大値の 20 より大きい要素は配列内に存在しないため、20 に対しては -1 が出力されます。解決のアプローチこの問題は C++ STL の set(セット)を使うと簡単に解決できます。set は二分探索木をベース

  2. C++で配列内の数値の頻度(出現回数)を求める方法

    配列に n 個の異なる要素が格納されているとします。この配列の中から、特定の要素が何回出現するか(頻度)を調べたい場合があります。例えば、配列 A = [5, 12, 26, 5, 3, 4, 15, 5, 8, 4] の中で「5」の頻度を調べると、答えは 3 になります。アルゴリズムの考え方この問題は、次の手順で解くことができます。1. 配列を左端から順に走査します。2. 現在の要素が調べたい数値と一致したら、カウンターを1つ増やします。3. 一致しない場合は、そのまま次の要素へ進みます。4. 配列の最後まで走査したら、カウンターの値が頻度となります。このアルゴリズムの計算量は O(n) で