详解二分法查找目标值/二分法查找上下界的两种写法

文章讨论了在整数数组中使用二分查找算法时,针对不同查找需求(等于、小于等于、大于等于)对左边界和右边界更新的优化策略,强调了在升序区间查找≤时应采用(l≤r)写法以避免错误。
摘要由CSDN通过智能技术生成

本文中默认数组呈升序。

💡 绝对不能使用left = cur这种更新,由于整数除法取下界,left不更新会导致循环无法结束

寻找与target相等

  1. 可以用(l < r)写法,末尾r==l需要检查是否满足条件,满足则输出,不满足则输出-1
  2. 可以用(l<=r) 写法,末尾输出r 不需要检查是否满足条件,不满足的情况下r为-1,因此结果r可能会超出数组索引,注意不要对此进行nums[r]的检查
// ==
// Method1 : left=mid+1, right=mid, 此时最优解为最后的重合解(若可行)
// 遍历直至left = right,左右重合时退出循环,此时重合解若可行,即为答案
int BinSearch1(vector<int> &nums, int target) {
    int l = 0;
    int r = nums.size()-1;
    int mid;
    while (l < r) {
        mid = (l+r)/2;
        if (nums[mid] == target)
            return mid;
        else if (nums[mid] < target) {
            l = mid + 1;
        }
        else
            r = mid;
    }
    if (nums[r] == target)
        return r;
    return -1;
}

// ==
// Method2 : left=mid+1, right=mid-1, 此时最优解需要另外记录
// 遍历直至left > right,左右重合时仍然进入循环并进行结果记录
int BinSearch2(vector<int> &nums, int target) {
    int l = 0;
    int r = nums.size()-1;
    int mid;
    while (l <= r) {
        mid = (l+r)/2;
        if (nums[mid] == target)
            return mid;
        else if (nums[mid] < target) {
            l = mid + 1;
        }
        else
            r = mid - 1;
    }
    return r;
}

寻找最后一个小于(等于)target

💡 需要使用(l<=r) 的写法

因为查找≤时不满足条件更新的是右界,满足条件下更新左界;

如果采用(l<r)写法:

  • 更新左界如果使用l = mid+1 ,由于mid此时满足条件,会导致新区间错失满足条件的点,答案错误
  • 如果使用l=mid,由于mid=(l+r)/2整数除法取下界,某些情况下左界会不更新,从而引起循环无法结束,程序错误

综上,在升序区间查找≤时只能采用(l≤r) 的写法,并通过r输出最终结果:若无满足条件的元素,将会使得r==-1

// <
int BinLBound(vector<int> &nums, int target) {
    int l = 0;
    int r = nums.size()-1;
    int mid;
    while (l <= r) {
        mid = (l+r)/2;
        // 先更新不满足条件
        if (nums[mid] >= target) {
            r = mid - 1;
        }
        else
            l = mid + 1;
    }
    return r;
}

// <=
int BinLEBound(vector<int> nums, int target) {
    int l = 0;
    int r = nums.size()-1;
    int mid;
    while (l <= r) {
        mid = (l+r)/2;
        if (nums[mid] > target)
            r = mid - 1;
        else
            l = mid + 1;
    }
    return r;
}

寻找第一个大于(等于)target

💡 需要使用(l<r) 的写法

// >
int BinHBound(vector<int> &nums, int target) {
    int l = 0;
    int r = nums.size()-1;
    int mid;
    while (l < r) {
        mid = (l+r)/2;
        if (nums[mid] <= target)
            l = mid + 1;
        else
            r = mid;
    }
    if (nums[r] > target)
        return r;
    return -1;
}
// >=
int BinHEBound(vector<int> &nums, int target) {
    int l = 0;
    int r = nums.size()-1;
    int mid;
    while (l < r) {
        mid = (l+r)/2;
        if (nums[mid] < target)
            l = mid + 1;
        else
            r = mid;
    }
    if (nums[r] >= target)
        return r;
    return -1;
}

整体测试代码

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> nums{-5, 0, 1, 2, 5, 10, 30, 90};
    int target = 90;
    cout << BinSearch1(nums, target) << " " << BinSearch2(nums, target) << endl;
    cout << BinLBound(nums, target)  << " " << BinLEBound(nums, target) << endl;
    cout << BinHBound(nums, target)  << " " << BinHEBound(nums, target);
    return 0;
}

二分法查找(Binary Search),也称为折半查找,是一种在有序数组中寻找特定元素的搜索算法。它的基本思想是从数组的中间元素开始,如果中间元素正好是要找的目标值,则搜索结束;如果目标值小于中间元素,就在数组左半部分继续查找;如果目标值大于中间元素,则在右半部分查找。这个过程会不断将搜索范围缩小一半,直到找到目标值或者搜索范围为空。 下面是C语言中的二分法查找算法的基本步骤: ```c #include <stdio.h> int binarySearch(int arr[], int left, int right, int target) { if (right >= left) { int mid = left + (right - left) / 2; // 计算中间索引 // 如果中间元素就是目标值,返回其索引 if (arr[mid] == target) return mid; // 如果目标值小于中间元素,向左半部分查找 else if (arr[mid] > target) return binarySearch(arr, left, mid - 1, target); // 否则,在右半部分查找 else return binarySearch(arr, mid + 1, right, target); } // 如果搜索范围为空,表示目标值不存在于数组中 return -1; } int main() { int arr[] = {1, 3, 5, 7, 9}; int n = sizeof(arr) / sizeof(arr); int target = 5; int result = binarySearch(arr, 0, n - 1, target); if (result != -1) printf("元素在数组中的位置: %d\n", result); else printf("元素不在数组中.\n"); return 0; } ``` 当你调用`binarySearch`函数并传入数组、初始和结束索引以及目标值,它将返回目标值在数组中的位置,如果没有找到则返回-1。执行该代码后,你会得到目标值5在数组中的位置3。如果目标值不存在于数组中,函数会告知你“元素不在数组中”。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值