🎯
【Java】二分探索2
例題
サイズn
の配列a
の要素の中には、サイズq
の配列k
の各要素k[i]
以上の個数は何個あるか求めよ。
例題の値
n = 10
a = 10 9 8 7 6 5 4 3 2 1
q = 2
k = 5 7
例題の答え
k[0] = 5
の場合の答えは、下記の6個。
5 6 7 8 9 10
k[1] = 7
の場合の答えは、下記の4個。
7 8 9 10
アルゴリズム
- 考え方
- 配列
a
を昇順にソート -
x
未満とx
以上の境界を探し、x
以上の要素数を求める - 境界の探すために二分探索を使用
- 配列
- 二分探索による境界の探し方
ソートされた配列a
と境界の関係性は、下記の通り| a[0] | a[1] | … | a[n - 2] | a[n - 1] | 0 1 2 n-2 n-1 n
- 境界の左端
l = 0
、境界の右端r = n
として、二分探索を開始 -
l == r
になるまで境界の位置を二分探索 →l != r
の間は探索を続ける - 中央の境界を
mid
=(l + r) / 2
(切り捨て)とする - 境界の位置は
mid
より右なのか左なのかを判定
- 境界の左端
- 二分探索の条件判定
-
a[mid]
>=x
なら境界はその位置かそれより左-
r
=mid
でr
を更新
-
-
a[mid]
<x
なら境界はそれより右-
l
=mid + 1
でl
を更新
-
-
- 境界の位置と答えについて
-
x
未満とx
以上の境界の位置はl
(またはr
、なぜなら境界の位置はl == r
だから) -
x
以上の要素数はn - l
-
コード例
import java.util.*;
public class Main {
// メソッド binarySearch(a, n, x) を定義
static int binarySearch(int[] a, int n, int x) {
// 変数 l = 0, r = n で初期化
int l = 0, r = n;
// l と r が一致しない間
while (l != r) {
// 中央の要素 mid に (l + r) / 2 を代入
int mid = (l + r) / 2;
// もし a[mid] が x 以上なら
if (a[mid] >= x) {
// r を mid で更新
r = mid;
// そうでなければ
} else {
// left を mid + 1 で更新
l = mid + 1;
}
}
// l を返す
return l;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();
}
// 配列 a を昇順にソート
Arrays.sort(a);
int q = sc.nextInt();
int[] k = new int[q];
for (int i = 0; i < q; i++) {
k[i] = sc.nextInt();
// binarySearchメソッドを呼び出して、n - l を出力
System.out.println(n - binarySearch(a, n, k[i]));
}
}
}
Discussion