2025.2.3
例1:查找有序数组中某个元素;
int binarySearch(vector& arr, int target){
//接受有序数组arr和目标值target
int left=0,right=arr.size()-1;
//定义左指针指向数组起始位置(即0下标),右指针为数组最后一个元素的下标
while(left<=right){//循环条件:左指针没有越过右指针
int mid=left+(right-left)/2;//定义中间位置的索引mid
if(arr[mid]==target){//如果中间位置的元素等于目标值
return mid;//返回中间位置的索引(元素下标)
}else if(arr[mid]
例2: 查找最左侧目标值;
int binarySearchleft(vector &arr, int target)
{
int left = 0, right = arr.size() - 1;
int res = -1;
while (left <= right)
{
int mid = left + (right - left) / 2;
if (arr[mid] == target)
{
res = mid;
right = mid - 1;
}
else if (arr[mid] < target)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
return res;
}
例3:查找最右侧目标值;
int binarySearchRight(const vector& arr, int target) {
int left = 0, right = arr.size() - 1;
int res = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
res = mid;
left = mid + 1;
}
else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return res;
}
ps:使用left+(right-left)/2代替(left+right)/2,可以防止整数溢出,因为当left和right较大的时候,二者相加可能超过int范围
例1:求平方根;
int sqrt(int x)
{
if (x == 0 || x == 1)
return x;
// 边界情况
int ans = 0;
int left = 0, right = x; // 初始范围
while (left <= right)
{
int mid = left + (right - left) / 2;
if (mid * mid <= x)
{ // 防止溢出
ans = mid;
left = mid + 1; // 继续尝试更大的值
}
else
{
right = mid - 1; // 继续尝试更小的值
}
}
return ans;
}
例2:找阈值k
非负数组nums,找最小阈值k,使得数组大于k的元素都被替换为k后,数组总和不超过target目标值
int findK(const vector &arr, int target)
{
// 已知结果范围:阈值最小值为0,最大值为maxelement
// 二分验证:每次取中间值mid,计算和
// 如总和小于等于target,则mid可能是结果,继续在[left,mid]区间内查找
int left = 0, right = *max_element(arr.begin(), arr.end());
int ans = right; // 初始化为最大值,假设原数组中所有元素和小于等于target
while (left <= right)
{
int mid = left + (right - left) / 2; // 从中间值开始查找
ll sum = 0; // 记录总和
bool check = false;
for (auto p : arr)
{
if (p > mid)
{
sum += mid; // 如果大于mid,则替换为mid
}
else
{
sum += p;
}
}
if (sum <= target)
{
ans = mid; // 记录当前可行的值
right = mid - 1; // 继续尝试更小的k
}
else
{
left = mid + 1; // 继续尝试更大的k
}
}
return ans;
}
应用场景:有序数组,有序vector等;
1.lower_bound;(最左目标值)
返回第一个大于或等于目标值的元素位置。
如果目标值不存在,则返回第一个大于目标值的元素位置。
如果所有元素都小于目标值,则返回范围的末尾位置。
2.upper_bound;(最右目标值的下一个)
返回第一个大于目标值的元素位置。
如果目标值不存在,则返回第一个大于目标值的元素位置。
如果所有元素都小于目标值,则返回范围的末尾位置。
例:洛谷:P2249 【深基13.例1】查找
格式:
//示例:数组arr={1,3,5,7,7,9,11}
//lower_bound(arr.begin(),arr.end(),7)返回第一个7的位置:即3
//lower_bound(arr.begin(),arr.end(),8)返回第一个大于8的位置:即5
常用写法:
vector nums = {1, 3, 5, 7, 9, 11};
auto it = lower_bound(nums.begin(), nums.end(), 6);
if (it != nums.end()) {
int index = it - nums.begin(); // 计算索引,即元素位置
cout << "Index: " << index << ", Value: " << *it << endl;
} else {
cout << "No element >= 6 found." << endl;
}
//输出:Index: 3, Value: 7;
//即:返回元素位置序号:index
//返回元素本身:*it
1.二维二分
例1:判断元素是否存在矩阵中;
// 从右上角开始查找
bool searchMatrix(vector>& arr, int target) {
if(arr.empty() || arr[0].empty()) return false;
//边界判断:如果数组为空或数组的第一行为空,则返回false
int m=arr.size(),n=arr[0].size();
//m为行数,n为列数
int row=0,col=n-1;//指针从右上角开始查找
while(row=0){
//行增加,列减少,当指针越界时,说明没找到
if(arr[row][col]==target)
return true;
//如果找到,返回true
else if(arr[row][col]>target)
col--;
//如果当前值大于target,则列减少,向左移动
else
row++;
//如果当前值小于target,则行增加,向下移动
}
return false;
}