Skip to content

Commit bf8d5fd

Browse files
committed
[yzx]1006:二分查找_python
1 parent f4061a7 commit bf8d5fd

File tree

2 files changed

+213
-0
lines changed

2 files changed

+213
-0
lines changed

TODO.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## v1
44

55
- [ ] 完善文档细节
6+
- [ ] python和C++实现
67
- [ ] 工程实现用到的算法解析
78
- [ ] 周赛计划
89
- [ ] 面试体系计划

basic_algorithm/binary_search.md

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
> 给定一个  n  个元素有序的(升序)整型数组  nums 和一个目标值  target  ,写一个函数搜索  nums  中的 target,如果目标值存在返回下标,否则返回 -1。
2121
22+
**C++版本**
2223
```cpp
2324
// 二分搜索最常用模板
2425
int search(vector<int>& nums, int target) {
@@ -40,6 +41,22 @@ int search(vector<int>& nums, int target) {
4041
return -1;
4142
}
4243
```
44+
**python3版本**
45+
```python
46+
class Solution:
47+
def search(self, nums: List[int], target: int) -> int:
48+
left = 0
49+
right = len(nums) - 1
50+
while left + 1 < right:
51+
mid = left + (right - left) // 2
52+
if nums[mid] == target: return mid
53+
elif nums[mid] < target: left = mid
54+
else: right = mid
55+
56+
if nums[left] == target: return left
57+
if nums[right] == target: return right
58+
return -1
59+
```
4360

4461
大部分二分查找类的题目都可以用这个模板,然后做一点特殊逻辑即可
4562

@@ -72,6 +89,61 @@ int search(vector<int>& nums, int target) {
7289
```
7390
7491
## 常见题目
92+
### [x的平方根](https://leetcode.cn/problems/sqrtx/)
93+
> 给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
94+
> 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
95+
> 注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
96+
97+
**Python版本**
98+
```python
99+
class Solution:
100+
def mySqrt(self, x: int) -> int:
101+
if x == 0: return 0
102+
left, right = 1, x//2 + 1
103+
while left + 1 < right:
104+
mid = left + (right - left) // 2
105+
if mid * mid == x: return mid
106+
elif mid * mid < x: left = mid
107+
else: right = mid
108+
109+
if left * left > x: return left - 1
110+
elif right * right <= x: return right
111+
else: return left
112+
113+
```
114+
115+
### [猜数字大小](https://leetcode.cn/problems/guess-number-higher-or-lower/)
116+
> 猜数字游戏的规则如下:
117+
> 每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
118+
> 如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。
119+
> 你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-1,1 或 0):
120+
121+
> -1:我选出的数字比你猜的数字小 pick < num
122+
123+
> 1:我选出的数字比你猜的数字大 pick > num
124+
125+
> 0:我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num
126+
127+
**Python版本**
128+
```python
129+
# The guess API is already defined for you.
130+
# @param num, your guess
131+
# @return -1 if my number is lower, 1 if my number is higher, otherwise return 0
132+
# def guess(num: int) -> int:
133+
134+
class Solution:
135+
def guessNumber(self, n: int) -> int:
136+
left, right = 1, n
137+
while left + 1 < right:
138+
mid = left + (right - left) // 2
139+
if guess(mid) == 0: return mid
140+
elif guess(mid) == -1: right = mid
141+
else: left = mid
142+
if guess(left) == 0: return left
143+
else: return right
144+
145+
```
146+
75147

76148
### [search-for-range](https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/)
77149

@@ -80,6 +152,65 @@ int search(vector<int>& nums, int target) {
80152
81153
思路:核心点就是找第一个 target 的索引,和最后一个 target 的索引,所以用两次二分搜索分别找第一次和最后一次的位置
82154

155+
**Python3版本**
156+
```python
157+
class Solution:
158+
def searchRange(self, nums: List[int], target: int) -> List[int]:
159+
if len(nums) == 0: return [-1, -1]
160+
161+
left, right = 0, len(nums) - 1
162+
while left + 1 < right:
163+
mid = left + (right - left) // 2
164+
if nums[mid] < target: left = mid
165+
elif nums[mid] > target: right = mid
166+
else:
167+
left = mid
168+
right = mid
169+
while left > 0 and nums[left-1] == target: left = left - 1
170+
while right < len(nums) - 1 and nums[right+1] == target: right = right + 1
171+
return [left, right]
172+
if nums[left] == target:
173+
if nums[right] == target: return [left, right]
174+
else: return [left, left]
175+
else:
176+
if nums[right] == target: return [right, right]
177+
else: return [-1, -1]
178+
```
179+
180+
```python
181+
class Solution:
182+
def searchRange(self, nums: List[int], target: int) -> List[int]:
183+
if len(nums) == 0: return [-1, -1]
184+
'''
185+
分解成找两次,找最左边一次,找最右边一次
186+
'''
187+
left = findTarget(nums, target, True)
188+
if left == -1: return [-1, -1]
189+
right = findTarget(nums, target, False)
190+
return [left, right]
191+
192+
def findTarget(nums, target, find_left):
193+
left, right = 0, len(nums) - 1
194+
while left + 1 < right:
195+
mid = left + (right - left) // 2
196+
if nums[mid] < target: left = mid
197+
elif nums[mid] > target: right = mid
198+
else:
199+
if find_left: right = mid
200+
else: left = mid
201+
202+
if find_left:
203+
if nums[left] == target: return left
204+
elif nums[right] == target: return right
205+
else: return -1
206+
else:
207+
if nums[right] == target: return right
208+
elif nums[left] == target: return left
209+
else: return -1
210+
211+
```
212+
213+
**C++版本**
83214
```cpp
84215
vector<int> searchRange(vector<int>& nums, int target) {
85216
if(nums.empty()) return {-1, -1};
@@ -170,6 +301,26 @@ bool searchMatrix(vector<vector<int>>& matrix, int target) {
170301
> 假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。
171302
> 你可以通过调用  bool isBadVersion(version)  接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
172303
304+
**Python3版本**
305+
```python
306+
# The isBadVersion API is already defined for you.
307+
# def isBadVersion(version: int) -> bool:
308+
309+
class Solution:
310+
def firstBadVersion(self, n: int) -> int:
311+
left, right = 1, n
312+
313+
while left + 1 < right:
314+
mid = left + (right - left) // 2
315+
if not isBadVersion(mid): left = mid
316+
else: right = mid
317+
318+
if isBadVersion(left): return left
319+
else: return right
320+
321+
```
322+
323+
**C++版本**
173324
```cpp
174325
int firstBadVersion(int n) {
175326
int left = 1, right = n;
@@ -187,7 +338,22 @@ int firstBadVersion(int n) {
187338
188339
> 假设按照升序排序的数组在预先未知的某个点上进行了旋转( 例如,数组  [0,1,2,4,5,6,7] 可能变为  [4,5,6,7,0,1,2] )。
189340
> 请找出其中最小的元素。
341+
**Python版本**
342+
```python
343+
class Solution:
344+
def findMin(self, nums: List[int]) -> int:
345+
left, right = 0, len(nums) - 1
346+
if nums[left] <= nums[right]: return nums[left] # 说明还是升序排列
347+
348+
while left + 1 < right:
349+
mid = left + (right - left) // 2
350+
if nums[mid] >= nums[right]: left = mid
351+
else: right = mid
352+
353+
return min(nums[left], nums[right])
354+
```
190355

356+
**C++版本**
191357
```cpp
192358
int findMin(vector<int>& nums) {
193359
if(nums.empty()) return 0;
@@ -236,6 +402,28 @@ int findMin(vector<int>& nums) {
236402
> 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回  -1 。
237403
> 你可以假设数组中不存在重复的元素。
238404
405+
**Python版本**
406+
```python
407+
class Solution:
408+
def search(self, nums: List[int], target: int) -> int:
409+
left, right = 0, len(nums) - 1
410+
411+
while left + 1 < right:
412+
mid = left + (right - left) // 2
413+
if nums[mid] == target: return mid
414+
if nums[mid] > nums[left]:
415+
if target >= nums[left] and target <= nums[mid]: right = mid
416+
else: left = mid
417+
else:
418+
if target <= nums[right] and target >= nums[mid]: left = mid
419+
else: right = mid
420+
421+
if nums[left] == target: return left
422+
elif nums[right] == target: return right
423+
else: return -1
424+
```
425+
426+
**C++版本**
239427
```cpp
240428
int search(vector<int>& nums, int target) {
241429
if(nums.empty()) return -1;
@@ -264,6 +452,30 @@ int search(vector<int>& nums, int target) {
264452
265453
> 面试时,可以直接画图进行辅助说明,空讲很容易让大家都比较蒙圈
266454
455+
### [寻找峰值](https://leetcode.cn/problems/find-peak-element/)
456+
> 峰值元素是指其值严格大于左右相邻值的元素。
457+
> 给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
458+
> 你可以假设 nums[-1] = nums[n] = -∞ 。
459+
> 你必须实现时间复杂度为 O(log n) 的算法来解决此问题。
460+
思路:规定了算法复杂度,那就是二分匹配法
461+
462+
**Python3版本**
463+
```python
464+
class Solution:
465+
def findPeakElement(self, nums: List[int]) -> int:
466+
left, right = 0, len(nums) - 1
467+
while left + 1 < right:
468+
mid = left + (right - left) // 2
469+
if nums[mid] < nums[mid+1]: left = mid
470+
else: right = mid
471+
472+
if nums[left] < nums[right]: return right
473+
else: return left
474+
```
475+
476+
**前面几道题说明了,二分匹配中,不一定直接对比mid和target, left和mid, mid本身, mid和相邻(mid+1),都是能做compare的。**
477+
478+
267479
### [search-in-rotated-sorted-array-ii](https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/)
268480

269481
> 假设按照升序排序的数组在预先未知的某个点上进行了旋转。

0 commit comments

Comments
 (0)