Skip to content

Commit e8ff355

Browse files
二分查找
1 parent 4034b05 commit e8ff355

File tree

2 files changed

+283
-256
lines changed

2 files changed

+283
-256
lines changed

data_structure/二分查找.md

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
## List-binarysearch
2+
### 二分查找
3+
#### 解题步骤
4+
1. 确定二分左右边界
5+
2. 设计一个性质使得可以将区间划分成两段(要求的点在其中一段的端点)
6+
3. 区间更新
7+
#### 二分查找模板
8+
```
9+
bool check(int x) // 检查x是否满足某种性质
10+
int bsearch_1(int l, int r){
11+
while (l < r){
12+
int mid = l + r >> 1;
13+
if (check(mid)) r = mid;
14+
else l = mid + 1;
15+
}
16+
return l;
17+
}
18+
19+
int bsearch_2(int l, int r){
20+
while (l < r){
21+
int mid = l + r + 1>> 1;
22+
if (check(mid)) l = mid;
23+
else r = mid - 1;
24+
}
25+
return l;
26+
}
27+
```
28+
#### leetcode.704
29+
- 链接<https://leetcode.cn/problems/binary-search/>
30+
- leetcode解题代码
31+
```
32+
class Solution {
33+
public:
34+
int search(vector<int>& nums, int target) {
35+
int l = 0, r = nums.size() - 1;
36+
while (l < r){
37+
int mid = (l + r) / 2;
38+
if (nums[mid] >= target) r = mid;
39+
else l = mid + 1;
40+
}
41+
if (nums[l] == target) return l;
42+
return -1;
43+
}
44+
};
45+
```
46+
#### leetcode.278
47+
- 链接<https://leetcode.cn/problems/first-bad-version/>
48+
- leetcode解题代码
49+
```
50+
// The API isBadVersion is defined for you.
51+
// bool isBadVersion(int version);
52+
53+
class Solution {
54+
public:
55+
int firstBadVersion(int n) {
56+
long l = 1, r = n;
57+
while (l < r){
58+
int mid = (l + r) / 2;
59+
if (isBadVersion(mid)) r = mid;
60+
else l = mid + 1;
61+
}
62+
return l;// 返回的是第一个错误的版本
63+
}
64+
};
65+
```
66+
#### leetcode.35
67+
- 链接<https://leetcode.cn/problems/search-insert-position/>
68+
- leetcode解题代码
69+
```
70+
class Solution {
71+
public:
72+
int searchInsert(vector<int>& nums, int target) {
73+
int n = nums.size();
74+
if (target > nums[n - 1]) return n;
75+
int l = 0, r = n - 1;
76+
while (l < r){
77+
int mid = (l + r) / 2;
78+
if (nums[mid] >= target) r = mid;
79+
else l = mid + 1;
80+
}
81+
return l;
82+
}
83+
};
84+
```
85+
#### leetcode.69
86+
- 链接<https://leetcode.cn/problems/sqrtx/submissions/>
87+
- leetcode解题代码
88+
```
89+
class Solution {
90+
public:
91+
int mySqrt(int x) {
92+
if (x <= 1) return x;
93+
long l = 1, r = x;
94+
while (l < r){
95+
int mid = l + r + 1 >> 1;
96+
if (mid <= x / mid) l = mid;// 下取整,取第一个小于等于根号下x的值
97+
else r = mid - 1;
98+
}
99+
100+
return l;
101+
}
102+
};
103+
```
104+
#### leetcode.367
105+
- 链接<https://leetcode.cn/problems/valid-perfect-square/>
106+
- 注意:与上一题区别在于只是判断是否存在完全平方数,不需要上取整或者下取整求完全平方数,所以使用模板一或者模板二均可
107+
- leetcode解题代码
108+
```
109+
class Solution {
110+
public:
111+
bool isPerfectSquare(int num) {
112+
long l = 1, r = num;
113+
while (l < r){
114+
int mid = l + r + 1 >> 1;
115+
if (mid <= num / mid) l = mid;
116+
else r = mid - 1;
117+
}
118+
return r * r == num;
119+
}
120+
};
121+
```
122+
#### leetcode.34
123+
- 链接<https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/>
124+
- leetcode解题代码
125+
```
126+
class Solution {
127+
public:
128+
vector<int> searchRange(vector<int>& nums, int target) {
129+
if (nums.empty()) return {-1, -1};
130+
int l = 0, r = nums.size() - 1;
131+
while (l < r){
132+
int mid = l + r >> 1;
133+
// 找到>=target的第一个数
134+
if (nums[mid] >= target) r = mid;
135+
else l = mid + 1;
136+
}
137+
138+
if (nums[l] != target) return {-1, -1};
139+
int L = l;
140+
141+
l = 0, r = nums.size() - 1;
142+
while (l < r){
143+
int mid = l + r + 1 >> 1;
144+
// 找到<=target的第一个数
145+
if (nums[mid] <= target) l = mid;
146+
else r = mid - 1;
147+
}
148+
return {L, r};
149+
}
150+
};
151+
```
152+
#### leetcode.74
153+
- 链接<https://leetcode.cn/problems/search-a-2d-matrix/>
154+
- 解题思路:将二维矩阵展成一维数组,二分
155+
- 注意:矩阵下标(i,j)转化为一维数组下标
156+
- leetcode解题代码
157+
```
158+
class Solution {
159+
public:
160+
bool searchMatrix(vector<vector<int>>& matrix, int target) {
161+
if (matrix.empty()) return false;
162+
int n = matrix.size(), m = matrix[0].size();
163+
int l = 0, r = n * m - 1;
164+
while (l < r){
165+
int mid = l + r >> 1;
166+
// 将矩阵下标转换为数组下标
167+
if (matrix[mid / m][mid % m] >= target) r = mid;
168+
else l = mid + 1;
169+
}
170+
171+
if (matrix[l / m][l % m] == target) return true;
172+
return false;
173+
}
174+
};
175+
```
176+
#### leetcode.153
177+
- 链接<https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/>
178+
- 解题思路:找到数组的二段性(前段的值均大于数组的最后一位,后段的值均小于等于数组的最后一位,并且最小的点在后段的端点处)
179+
- leetcode解题代码
180+
```
181+
class Solution {
182+
public:
183+
int findMin(vector<int>& nums) {
184+
int l = 0, r = nums.size();
185+
while (l < r){
186+
int mid = l + r >> 1;
187+
if (nums[mid] <= nums.back()) r = mid;
188+
else l = mid + 1;
189+
}
190+
return nums[l];
191+
}
192+
};
193+
```
194+
#### leetcode.33
195+
- 链接<https://leetcode.cn/problems/search-in-rotated-sorted-array/>
196+
- 解题思路:由于没有二段性不能直接二分,先找到数组的最小值(参考上一题),找到目标值所在区间,在对应区间内二分找目标值
197+
- leetcode解题代码
198+
```
199+
class Solution {
200+
public:
201+
int search(vector<int>& nums, int target) {
202+
if (nums.empty()) return -1;
203+
// 找到最小值
204+
int l = 0, r = nums.size() - 1;
205+
while (l < r){
206+
int mid = (l + r) / 2;
207+
if (nums[mid] <= nums.back()) r = mid;
208+
else l = mid + 1;
209+
}
210+
// 判断目标值所在区间
211+
if (target <= nums.back()) r = nums.size() - 1;
212+
else l = 0, r --;
213+
// 在所在区间找目标值
214+
while (l < r){
215+
int mid = (l + r) / 2;
216+
if (nums[mid] >= target) r = mid;
217+
else l = mid + 1;
218+
}
219+
if (nums[l] == target) return l;
220+
return -1;
221+
}
222+
};
223+
```
224+
***
225+
下列题目没有二段性,但仍然可以通过二分每次缩小一般的搜索区间找到答案
226+
#### leetcode.162
227+
- 链接<https://leetcode.cn/problems/find-peak-element/>
228+
- 解题思路:如果二分的中点的值比中点右边的值小,那么右边一定存在峰值,同理,如果二分的中点的值比中点右边的值大,那么左边一定存在峰值
229+
- leetcode解题代码
230+
```
231+
class Solution {
232+
public:
233+
int findPeakElement(vector<int>& nums) {
234+
int l = 0, r = nums.size() - 1;
235+
while (l < r){
236+
int mid = l + r >> 1;
237+
// 说明左边一定有峰值
238+
if (nums[mid] > nums[mid + 1]) r = mid;
239+
else l = mid + 1;
240+
}
241+
return l;
242+
}
243+
};
244+
245+
class Solution {
246+
public:
247+
int findPeakElement(vector<int>& nums) {
248+
int l = 0, r = nums.size() - 1;
249+
while (l < r){
250+
int mid = l + r >> 1;
251+
// 说明右边一定有峰值
252+
if (nums[mid] < nums[mid + 1]) l = mid + 1;
253+
else r = mid;
254+
}
255+
return l;
256+
}
257+
};
258+
```
259+
#### leetcode.287
260+
- 链接<https://leetcode.cn/problems/find-the-duplicate-number/>
261+
- 解题思路:抽屉原理,n+1个苹果放进n个抽屉中必然有一个抽屉放了两个苹果,抽屉为数据范围n,苹果为数字总数n+1,对数据范围二分,记录二分中点左侧的数字总数,和左边数据范围对比,如果数字总数大于数据范围,说明重复数在左侧,右侧同理
262+
- leetcode解题代码
263+
```
264+
class Solution {
265+
public:
266+
int findDuplicate(vector<int>& nums) {
267+
int l = 1, r = nums.size();
268+
while (l < r){
269+
int mid = l + r >> 1;
270+
271+
int cnt = 0;
272+
for (auto c: nums){
273+
if (c >= l && c <= mid)
274+
cnt ++;
275+
}
276+
if (cnt > mid - l + 1) r = mid;
277+
else l = mid + 1;
278+
}
279+
return l;
280+
}
281+
};
282+
```
283+
解题参考:<https://www.acwing.com/>

0 commit comments

Comments
 (0)