C++で二分探索により見つけられる要素の数を求める方法
問題概要
重複のない整数のリスト nums が与えられます。このリストの中から、標準的な二分探索(バイナリサーチ)の手順に従って実際に見つけ出せる整数が何個あるかを求めるのが課題です。
たとえば、入力が [2,6,4,3,10] の場合、出力は 3 になります。二分探索で 4 を探すと最初の反復で見つかり、2 と 10 は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) となります。
また、この問題の面白い点は、配列がソートされていなくても、二分探索の手順自体は機械的に進むため、偶然にも目的の値にたどり着くケースが存在することです。探索が成功するかどうかは、要素の配置と探索経路の組み合わせによって決まります。
-
C++で二分木を二分探索木(BST)へ変換する方法を解説
二分木(Binary Tree)とは二分木とは、木構造の各ノードが最大で2つの子ノードを持つことができる特別な木構造です。これらの子ノードは、それぞれ「左の子ノード」と「右の子ノード」と呼ばれます。シンプルな二分木の例は以下の通りです。二分探索木(BST)とは二分探索木(BST)は、以下のルールに従う特別な木構造です。左の子ノードの値は、常に親ノードの値より小さい右の子ノードの値は、常に親ノードの値より大きいすべてのノードが、それぞれ独立して二分探索木の性質を満たす二分探索木(BST)の例は以下の通りです。二分探索木は、検索や最小値・最大値の探索といった操作の計算量を削減するために用いられるデ
-
C++プログラムにおける二分探索(バイナリサーチ)の基本と実装
二分探索(バイナリサーチ)とは二分探索は「半区間探索」「対数探索」「バイナリチョップ」とも呼ばれる検索アルゴリズムで、ソート済みの配列の中から目的の値が存在する位置を効率的に見つけ出します。基本的な仕組みは非常にシンプルです。まず、探したい値(ターゲット値)を配列の中央の要素と比較します。一致しなかった場合は、ターゲット値が存在し得ない半分を丸ごと排除し、残りの半分に対して同様の比較を繰り返します。この「中央との比較」と「範囲の絞り込み」を続け、ターゲット値が見つかるか、検索範囲が空になる(=配列にその値が存在しない)かのどちらかで処理が終了します。アイデア自体は簡単ですが、正しく実装するには