二分法
概述
STL C++ 二分查找库
闭区间、左闭右开区间和开区间
class Solution {
// lower_bound 返回最小的满足 nums[i] >= target 的 i
// 如果数组为空,或者所有数都 < target,则返回 nums.size()
// 要求 nums 是非递减的,即 nums[i] <= nums[i + 1]
// 闭区间写法
int lower_bound(vector<int> &nums, int target) {
int left = 0, right = (int) nums.size() - 1; // 闭区间 [left, right]
while (left <= right) { // 区间不为空
// 循环不变量:
// nums[left-1] < target
// nums[right+1] >= target
int mid = left + (right - left) / 2;
if (nums[mid] < target)
left = mid + 1; // 范围缩小到 [mid+1, right]
else
right = mid - 1; // 范围缩小到 [left, mid-1]
}
return left; // 或者 right+1
}
// 左闭右开区间写法
int lower_bound2(vector<int> &nums, int target) {
int left = 0, right = nums.size(); // 左闭右开区间 [left, right)
while (left < right) { // 区间不为空
// 循环不变量:
// nums[left-1] < target
// nums[right] >= target
int mid = left + (right - left) / 2;
if (nums[mid] < target)
left = mid + 1; // 范围缩小到 [mid+1, right)
else
right = mid; // 范围缩小到 [left, mid)
}
return left; // 或者 right
}
// 开区间写法
int lower_bound3(vector<int> &nums, int target) {
int left = -1, right = nums.size(); // 开区间 (left, right)
while (left + 1 < right) { // 区间不为空
// 循环不变量:
// nums[left] < target
// nums[right] >= target
int mid = left + (right - left) / 2;
if (nums[mid] < target)
left = mid; // 范围缩小到 (mid, right)
else
right = mid; // 范围缩小到 (left, mid)
}
return right; // 或者 left+1
}
public:
vector<int> searchRange(vector<int> &nums, int target) {
int start = lower_bound(nums, target); // 使用其中一种写法即可
if (start == nums.size() || nums[start] != target)
return {-1, -1};
// 如果 start 存在,那么 end 必定存在
int end = lower_bound(nums, target + 1) - 1;
return {start, end};
}
};
作者:灵茶山艾府
链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/solutions/1980196/er-fen-cha-zhao-zong-shi-xie-bu-dui-yi-g-t9l9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
题目
34. 在排序数组中查找元素的第一个和最后一个位置
二分法写作技巧:
1、首先 while (left <= right) 怎么写取决于,left right 是闭区间还是开区间。
2、mid = (left + right) / 2; 这个是不影响的,所有区间都这么写
3、将三种方法写全,不要偷懒 。一开始我的 == 情况没有分开写导致了一大堆的问题
使用 STL 库
vector<int> searchRange(vector<int> &nums, int target) {
auto bound = equal_range(nums.begin(), nums.end(), target);
int left = bound.first - nums.begin();
int right = bound.second - nums.begin();
return {left, right};
}
我的解题思路
我的思路:
1、寻找第一个小于。当等于的时候,继续往左移。而不是 直接退出。知道找到最左一个满足条件的值
2、寻找第一个大于,跟1一样。
我的代码
#include "vector"
#include "set"
#include "iostream"
#include "algorithm"
#include "tuple"
#include "unordered_map"
using namespace std;
class Solution {
public:
// 找到左边第一个
int find_first(vector<int> &nums, int target) {
int result = -1;
int left = 0;
int right = nums.size() - 1;
int mid = 0;
while (left <= right) { // 在闭区间之中寻找 [left, right]
mid = (left + right) / 2;
if (nums[mid] == target){
result = mid;
right = mid -1 ; // 当找到一个时,继续往左边寻找
}else if (nums[mid] > target) {
right = mid -1 ;
} else if (nums[mid] < target) {
left = mid + 1;
}
}
return result;
}
// 找到右边最后一个
int find_last(vector<int> &nums, int target) {
int result = -1;
int left = 0;
int right = nums.size() - 1;
int mid = 0;
while (left <= right) {
mid = (left + right) / 2;
if (nums[mid] == target){
result = mid;
left = mid + 1;
}else if (nums[mid] > target) {
right = mid -1;
} else if (nums[mid] < target) {
left = mid + 1;
}
}
return result;
}
vector<int> searchRange(vector<int> &nums, int target) {
int left = find_first(nums, target);
int right = find_last(nums, target);
if (nums.size() == 0 || left > right) {
return {-1, -1};
}
return {left, right};
}
};
int main() {
std::cout << "Hello, World!" << std::endl;
Solution *a = new Solution();
vector<int> nums = {5, 7, 7, 8, 8, 10};
a->searchRange(nums, 8);
return 0;
}
704. Binary Search 704. 二分查找 🟢
我的解题思路和代码
1、一个简单的二分查找
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int mid = 0;
while (left <= right) {
mid = (left + right) / 2;
if (nums[mid] == target){
return mid;
}else if (nums[mid] > target) {
right = mid -1 ;
} else if (nums[mid] < target) {
left = mid + 1;
}
}
return -1;
}
};
使用STL库
#include "algorithm"
int searchRange(vector<int> &nums, int target) {
auto it = lower_bound(nums.begin(), nums.begin() + nums.size()-1, target);
int left = it - nums.begin();
return left;
}
剑指 Offer 53 - I. 在排序数组中查找数字 I
我的解题思路和代码:
1、用二分法找到第一个满足条件的值
2、然后用一次遍历找到所有的值
class Solution {
public:
// 找到左边第一个
int find_first(vector<int> &nums, int target) {
int left = 0;
int right = nums.size() - 1;
int mid = 0;
int result = -1;
while (left <= right) {
mid = (left + right) / 2;
if (nums[mid] == target){
result = mid;
right = mid-1;
}else if (nums[mid] > target) {
right = mid -1 ;
} else if (nums[mid] < target) {
left = mid + 1;
}
}
return result;
}
int search(vector<int>& nums, int target) {
int result = 0;
int left = find_first(nums, target);
if(left==-1){
return 0;
}
while (left<nums.size() && nums[left]==target){
left++;
result += 1;
}
return result;
}
};
官网题解
1、找到左右两边的值,然后取差值