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

C++で二分探索により見つけられる要素の数を求める方法

問題概要

重複のない整数のリスト nums が与えられます。このリストの中から、標準的な二分探索(バイナリサーチ)の手順に従って実際に見つけ出せる整数が何個あるかを求めるのが課題です。

たとえば、入力が [2,6,4,3,10] の場合、出力は 3 になります。二分探索で 4 を探すと最初の反復で見つかり、210 は2回の反復後に見つかるためです。

解き方のアプローチ

この問題は、リスト内の各要素を「探索対象」として実際に二分探索を実行し、その探索が成功するかどうかを確認するというシンプルな方針で解けます。具体的には、以下の手順に従います。

  • help() 関数を定義する:引数として探索対象の値 target と配列 nums を受け取ります。
  • low := 0 と初期化します。
  • high := nums のサイズ - 1 と初期化します。
  • low <= high の間、以下を繰り返します。
    • mid := low + (high - low) / 2 を計算します。
    • nums[mid]target と等しければ true を返します。
    • nums[mid] < target であれば low := mid + 1 とします。
    • それ以外の場合は high := mid - 1 とします。
  • ループを抜けたら false を返します。

メイン処理の流れ

  • 結果を格納する変数 ret := 0 を用意します。
  • nums の各要素 i について ret := ret + help(i, nums) を実行します。
  • 最後に ret を返します。

C++での実装例

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

#include <bits/stdc++.h>
using namespace std;
class Solution {
    public:
    bool help(int target, vector<int> & nums) {
        int low = 0;
        int high = nums.size() - 1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (nums[mid] == target)
            return true;
            if (nums[mid] < target) {
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }
        return false;
    }
    int solve(vector<int> & nums) {
        int ret = 0;
        for (int i : nums) {
            ret += help(i, nums);
        }
        return ret;
    }
};
main() {
    Solution ob;
    vector<int> v = {2,6,4,3,10};
    cout << (ob.solve(v));
}

入力

{2,6,4,3,10}

出力

3

補足:計算量とポイント

1つの要素に対する二分探索の計算量は O(log n) であり、リスト内の全要素 n 個それぞれについて探索を行うため、全体の計算量は O(n log n) となります。

また、この問題の面白い点は、配列がソートされていなくても、二分探索の手順自体は機械的に進むため、偶然にも目的の値にたどり着くケースが存在することです。探索が成功するかどうかは、要素の配置と探索経路の組み合わせによって決まります。

  1. C++で二分木を二分探索木(BST)へ変換する方法を解説

    二分木(Binary Tree)とは二分木とは、木構造の各ノードが最大で2つの子ノードを持つことができる特別な木構造です。これらの子ノードは、それぞれ「左の子ノード」と「右の子ノード」と呼ばれます。シンプルな二分木の例は以下の通りです。二分探索木(BST)とは二分探索木(BST)は、以下のルールに従う特別な木構造です。左の子ノードの値は、常に親ノードの値より小さい右の子ノードの値は、常に親ノードの値より大きいすべてのノードが、それぞれ独立して二分探索木の性質を満たす二分探索木(BST)の例は以下の通りです。二分探索木は、検索や最小値・最大値の探索といった操作の計算量を削減するために用いられるデ

  2. C++プログラムにおける二分探索(バイナリサーチ)の基本と実装

    二分探索(バイナリサーチ)とは二分探索は「半区間探索」「対数探索」「バイナリチョップ」とも呼ばれる検索アルゴリズムで、ソート済みの配列の中から目的の値が存在する位置を効率的に見つけ出します。基本的な仕組みは非常にシンプルです。まず、探したい値(ターゲット値)を配列の中央の要素と比較します。一致しなかった場合は、ターゲット値が存在し得ない半分を丸ごと排除し、残りの半分に対して同様の比較を繰り返します。この「中央との比較」と「範囲の絞り込み」を続け、ターゲット値が見つかるか、検索範囲が空になる(=配列にその値が存在しない)かのどちらかで処理が終了します。アイデア自体は簡単ですが、正しく実装するには