0%

二分查找法

二分查找法

二分查找法(Binary Search)是一种在有序数组或列表中快速查找目标值的算法。它通过将查找范围逐步减半,有效地减少了比较次数,时间复杂度为O(logN),适用于数据量较大且有序的场景。

左闭右闭区间 [left, right]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int binarySearchClosed(int target) {
int left = 0;
int right = n - 1; // 初始化右边界为数组最后一个索引
while (left <= right) { // 区间为 [left, right]
int mid = left + (right - left) / 2; // 防止溢出
if (arr[mid] > target)
right = mid - 1; // 缩小右边界
else if (arr[mid] < target)
left = mid + 1; // 缩小左边界
else
return mid; // 找到目标
}
return -1; // 未找到
}

左闭右开区间 [left, right)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int binarySearchOpen(int target) {
int left = 0;
int right = n; // 初始化右边界为 n(超出有效索引范围)
while (left < right) { // 区间为 [left, right)
int mid = left + (right - left) / 2; // 防止溢出
if (arr[mid] > target)
right = mid; // 缩小右边界,但不包括 mid
else if (arr[mid] < target)
left = mid + 1; // 缩小左边界
else
return mid; // 找到目标
}
return -1; // 未找到
}

变体

查找元素第一次出现的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int binarySearchFirstOccurrence(int target) {
int left = 0;
int right = n - 1;
int result = -1; // 用于记录目标值的第一个位置
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] > target) {
right = mid - 1;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
result = mid; // 记录当前匹配位置
right = mid - 1; // 继续向左查找
}
}
return result; // 返回找到的第一个位置,若未找到则为 -1
}

查找>=target的第一个元素的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int binarySearchFirstGE(int target) {
int left = 0;
int right = n - 1;
int result = -1; // 记录满足条件的最小索引
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] >= target) {
result = mid; // 记录当前索引
right = mid - 1; // 继续向左搜索
} else {
left = mid + 1;
}
}
return result; // 返回找到的第一个 >= target 的元素索引,未找到则返回 -1
}

查找<=target的最后一个元素的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int binarySearchLastLE(int target) {
int left = 0;
int right = n - 1;
int result = -1; // 记录满足条件的最大索引
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] <= target) {
result = mid; // 记录当前索引
left = mid + 1; // 继续向右搜索
} else {
right = mid - 1;
}
}
return result; // 返回找到的最后一个 <= target 的元素索引,未找到则返回 -1
}

查找函数的根

1
2
3
4
5
6
7
8
9
10
11
12
//分成多个小区间,分别查找
double BS(double l, double r){
while (r - l > 0.0001) {
double mid = (l + r) / 2;
if (f(l) * f(mid) <= 0) {
r = mid;
} else {
l = mid;
}
}
return (l + r) / 2;
}

查找在三角形中一个元素位于几行几列

https://ac.nowcoder.com/acm/contest/101921/C

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <bits/stdc++.h>
#define int long long
using namespace std;

int findrow(int x) {
int l = 1;
int r = 1e9;
int ans = -1;
while (l <= r) {
int mid = (l + r) / 2;
int sum = mid * (mid + 1) / 2;
if (sum >= x) {
r = mid - 1;
ans = mid;
} else {
l = mid + 1;
}
}
return ans;
}

void solve() {
int n, l, r;
cin >> n >> l >> r;
int l_row = findrow(l), r_row = findrow(r);
if (l_row == r_row) {
cout << "Yes" << endl;
} else if (l_row + 1 == r_row) {
int first_l_row = (l_row - 1) * l_row / 2 + 1;
int l_col = l - first_l_row + 1;
int first_r_row = (r_row - 1) * r_row / 2 + 1;
int r_col = r - first_r_row + 1;
if (l_col > r_col) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
} else {
cout << "No" << endl;
}
}

signed main() {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}

return 0;
}

查找等腰梯形

https://codeforces.com/problemset/problem/2061/B

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <bits/stdc++.h>
#define int long long
using namespace std;

// < x 的最后一个元素
int find(int begin, int n, vector<int>& arr, int key) {
int l = begin;
int r = n - 1;
int ans = -1;
while (l <= r) {
int mid = (l + r) / 2;
if (arr[mid] < key) {
ans = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
return ans;
}

void solve() {
int n;
cin >> n;
vector<int> arr(n);
map<int, int> cnt;

for (int i = 0; i < n; i++) {
cin >> arr[i];
cnt[arr[i]]++;
}

sort(arr.begin(), arr.end());

int sum = 0;
int a, b, c, d;

for (auto x : cnt) {
if (x.second >= 2) {
sum++;
if (sum == 1) {
a = x.first;
b = x.first;
}
else if (sum == 2) {
c = x.first;
d = x.first;
}
if (sum == 2) break;
}
}

if (sum >= 2) {
cout << a << " " << b << " " << c << " " << d << endl;
return;
} else if (sum == 0) {
cout << -1 << endl;
return;
} else {
// 在a, b确定的情况下查找c, d
// abs(c - d) < a + b
// 我们从左到右枚举 c, 然后从 c 以后的位置开始查找 d
// 这时候 d 总会比 c 大, 也就是说 d < a + b + c

// lower_bound
// 查找 >= x 的第一个元素

// upper_bound
// 查找 > x 的第一个元素

auto pos = lower_bound(arr.begin(), arr.end(), a);

// 使用erase后下标会发生变化
// 删除 a, b

arr.erase(pos);
arr.erase(pos);
n = arr.size();

// 使用 continue 可以减少if-else的嵌套

for (int i = 0; i < n; i++) {
c = arr[i];
if (i + 1 >= n) continue;
int pos_d = find(i + 1, n, arr, a + b + c);
if (pos_d == -1) continue;
else {
d = arr[pos_d];
cout << a << " " << b << " " << c << " " << d << endl;
return;
}
}
}

cout << -1 << endl;
}

signed main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}

return 0;
}