二分算法——模板

//二分算法

//题目:在排序数组中查找元素的第一个和最后一个位置

//解法一:暴力解法 -> 从前往后扫描数组
// 慢就慢在没有利用数组有序的特性

//解法二:二分算法
// 契机:发现解集中,存在二段性

//1. 查找起始位置
// 细节问题:
// 1.while循环里面的判断如何写
// while(left < right) 对
// while(left <= right) 错,会死循环
// 2.求中点的方式?
// (left + right) / 2 对 a[mid] >= t -> right = mid -> [left, right]
// (left + right + 1) / 2 错,会死循环 a[min] < t -> left = rid + 1 -> [left, right]
// 3.二分结束之后,相遇点的情况
// 需要判断一下,循环结束之后, 是否是我们想要的结果

//2.查找终止位置
// 细节问题:
// 1.while循环里面的判断条件?
// while(left < right)
// while(left <= right)
// 2.求中点的方式
// (left + right) / 2 错 死循环 a[mid] <= t -> left = mid -> [left, right]
// (left + right + 1) / 2 对 a[mid] > t -> right = mid - 1 -> [left, right]

//二分模板
// // ⼆分查找区间左端点
// int l = 1, r = n;
// while(l < r)
// {
// int mid = (l + r) / 2;
// if(check(mid)) r = mid;
// else l = mid + 1;
// }
// // ⼆分结束之后可能需要判断是否存在结果

// // ⼆分查找区间右端点
// int l = 1, r = n;
// while(l < r)
// {
// int mid = (l + r + 1) / 2;
// if(check(mid)) l = mid;
// else r = mid - 1;
// }
// // ⼆分结束之后可能需要判断是否存在结果

// 为了防⽌溢出,求中点时可以下⾯的⽅式:
// • mid = l + (r - l) / 2
// 【时间复杂度】
// 每次⼆分都会去掉⼀半的查找区域,因此时间复杂度为 logN 。

class Solution {
public:
vector searchRange(vector& nums, int target) {
// 1. 初始化数组长度,处理空数组边界
int n = nums.size();
if(n == 0) return{-1, -1};

// 2. 第一次二分:找左边界(第一个等于target的位置)
int left = 0, right = n - 1;
while(left < right){
int mid = (left + right) / 2; // 向下取整
if(nums[mid] >= target) right = mid; // 左边界在mid或左侧,收缩右边界
else left = mid + 1; // 左边界在mid右侧,收缩左边界
}
// 检查找到的位置是否真的是target(排除数组中无target的情况)
if(nums[left] != target) return{-1, -1};
int retleft = left; // 记录左边界

// 3. 第二次二分:找右边界(最后一个等于target的位置)
left = 0, right = n - 1; // 重置左右指针
while(left < right){
int mid = (left + right + 1) / 2; // 向上取整(关键!避免死循环)
if(nums[mid] <= target) left = mid; // 右边界在mid或右侧,收缩左边界
else right = mid - 1; // 右边界在mid左侧,收缩右边界
}

// 4. 返回结果:左边界 + 右边界
return {retleft, left};
}
};

posted @ 2026-03-05 13:00  无酒无剑  阅读(20)  评论(0)    收藏  举报