文章目录
- 二分模板题
- 二分的思想
- [C++ 版本的二分](#C++ 版本的二分)
- [Golang 版本的二分](#Golang 版本的二分)
- 例题:在排序数组中查找元素的第一个和最后一个位置
-
- 题目描述
- [C++ 版本代码](#C++ 版本代码)
- [Golang 版本代码](#Golang 版本代码)
二分模板题
704. 二分查找,这道题目是最经典的二分查找,使用于任何模板(如果你学的模板连这道题都套不上,那大概是模板有问题)
34. 在排序数组中查找元素的第一个和最后一个位置,一个合格的二分模板,需要能够应对这道题目的两种二分情况,我待会儿也会以这道题作为例题
二分的思想
我学算法也有一年了,二分相关的题目刷了也有 20 道以上,二分的模板也学了不下于 3 套,每一套都很有道理,但做他们选的题目是做对了,当遇到野生的二分题目的时候,时常失灵
我自己也在努力总结二分的本质,之前我一直认为二分的本质就是寻找单调性,但似乎并不是这样的,有单调性的题目确实一定可以用二分,但有些没有单调性的题目也可以用二分
其实二分的本质并不是单调性,当我们能将数据分成两个区间,一个区间不符合要求可以舍去,一个区间包含我们需要的答案,需要保留,这样的题目就能够使用二分
C++ 版本的二分
整数二分模板
模板一:用于左半区间不存在答案,而右半区间存在答案的情况,也就是在 [ left,mid ],[ mid + 1,right ]
cpp
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
模板二:用于左半区间存在答案,而右半区间不存在答案的情况,也就是在 [ left,mid - 1 ],[ mid,right ]
cpp
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
模板记忆方法:有 - 1,那求 mid 的时候就需要 + 1
Golang 版本的二分
整数二分模板
模板一:用于左半区间不存在答案,而右半区间存在答案的情况,也就是在 [ left,mid ],[ mid + 1,right ]
go
l, r := 0, len(nums)-1
for l < r {
mid := l+(r-l)/2
if check(mid) {
r = mid
} else {
l = mid + 1
}
}
模板二:用于左半区间存在答案,而右半区间不存在答案的情况,也就是在 [ left,mid - 1 ],[ mid,right ]
go
l, r = 0, len(nums)-1
for l < r {
mid := l+(r-l+1)/2
if check(mid) {
l = mid
} else {
r = mid - 1
}
}
例题:在排序数组中查找元素的第一个和最后一个位置
题目链接:34. 在排序数组中查找元素的第一个和最后一个位置
题目描述
C++ 版本代码
cpp
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
if (nums.size() == 0) return {-1, -1};
vector<int> ans;
int l = 0, r = nums.size() - 1;
while (l < r) {
int mid = l + r >> 1;
if (nums[mid] >= target) r = mid;
else l = mid + 1;
}
if (nums[l] != target) return {-1, -1};
ans.push_back(l);
l = 0, r = nums.size() - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (nums[mid] <= target) l = mid;
else r = mid - 1;
}
ans.push_back(l);
return ans;
}
};
Golang 版本代码
go
func searchRange(nums []int, target int) (ans []int) {
if len(nums) == 0 {
return []int{-1, -1}
}
l, r := 0, len(nums)-1
for l < r {
mid := l+(r-l)/2
if nums[mid] >= target {
r = mid
} else {
l = mid + 1
}
}
if nums[l] != target {
return []int{-1, -1}
}
ans = append(ans, l)
l, r = 0, len(nums)-1
for l < r {
mid := l+(r-l+1)/2
if nums[mid] <= target {
l = mid
} else {
r = mid - 1
}
}
ans = append(ans, l)
return ans
}