二分查找算法及其实例

二分查找算法及其实例

问题一:二分查找

  1. 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9 输出: 4 解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2 输出: -1 解释: 2 不存在 nums 中因此返回 -1
提示:
你可以假设 nums 中的所有元素是不重复的。 n 将在 [1, 10000]之间。 nums 的每个元素都将在 [-9999,9999]之间。

解题思路

  • 二分查找算法是通过不断缩小需要查找的目标区域,直到找到目标值,或者区域为空,结束循环
  • 具体来讲,先要找到左右边界然后(Right + Left) / 2即为当前查找区域的中点,通过判断中点值与目标target的大小关系,选择缩小哪一边的边界,每次至少能够排除当前区域的一半,这里需要注意左右边界在更新时不是直接等于 mid 而是等于 mid±1,否则会造成当区域大小为2时死循环
  • 以下是C++代码实现
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int Left = 0;
        int Right = nums.size()-1;
        while (Left <= Right)
        {
            int mid = (Right + Left) / 2;
            if (nums[mid] > target)
            {
                Right = mid - 1;
            }
            else if (nums[mid] < target)
            {
                Left = mid + 1;
            }
            else
            {
                return mid;
            }
        }
        return -1;
    }
};

问题二:第一个错误的版本

  1. 你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
  • 假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
  • 你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

示例 1:
输入:n = 5, bad = 4
输出:4
解释:调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true 所以,4 是第一个错误的版本。

示例 2:
输入:n = 1, bad = 1
输出:1

提示:
1 <= bad <= n <= 2^31 - 1

解题思路

  • 在二分查找的基础上需要调整目标值的判断方式,在此问题中所求目标值是没有唯一的参照物的,所以不能单纯i通过isBadVersion接口返回的bool值判断是否是首个错误的版本,而是需要多判断一次mid+1时的情况,通过两次判断锁定首个错误的版本
  • 具体来说就是当isBadVersion(mid)返回为false时表明mid的左边全是好的版本,那么范围就缩小到mid的右边了,如果此时isBadVersion(mid+1)返回为true这表示就在mid+1的位置出现了第一个错误的版本
// The API isBadVersion is defined for you.
bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
        long left = 1;
        long right = n;
        while(left<=right)
        {
            long mid = (left+right)/2;
            if(isBadVersion(mid) == true)
            {
               right = mid-1;
            }
            else if(isBadVersion(mid) == false)
            {
               //当二分区域的mid值不是错误版本时,证明首个错误版本就在(mid,right]之间,因此判断mid+1是否时首个错误版本
                if(isBadVersion(mid+1) == true)
                {
                    return mid + 1;
                }
                else
                {
                    left = mid + 1;
                }
            }
        }
        return 1;
    }
};

问题三:搜索插入位置

  1. 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(log n) 的算法。

示例 1:
输入: nums = [1,3,5,6], target = 5 输出: 2
示例 2:
输入: nums = [1,3,5,6], target = 2 输出: 1
示例 3:
输入: nums = [1,3,5,6], target = 7 输出: 4
提示:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
-104<= target <= 104
nums 为 无重复元素 的 升序 排列数组

解题思路

  • 此题思路与第一题类似但是多出了一种情况,就是当值不在数组中时需要返回需要插入的位置,因此我们在每次判断mid大于或者小于目标值后,还需要注意其相邻值是否小于或大于目标值,这里的相邻指的是在当前查找范围内的一侧的相邻值,如果一方大于另一方小于则表明此数在数组中不存在,插入位置就是当前的mid或者mid+1的位置
  • 若查找范围缩小为空仍然没找到对应位置,那么根据现在left或right的所在位置判断,如果left超过数组最右侧,则表示需要插入的元素在最右边,否则在最左边插入
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size()-1;
        while(left<=right)
        {
            int mid = (left+right)/2;
            if(nums[mid] == target)
            {
                return mid;
            }
            else if(nums[mid] > target)
            {
                if(mid-1>=0 && nums[mid-1] < target)
                {
                    return mid;
                }
                right = mid - 1;
            }
            else
            {
                if(mid+1<=nums.size()-1 && nums[mid + 1] > target)
                {
                    return mid + 1;
                }
                left = mid + 1;
            }
        }
        if(left>nums.size()-1)
        {
            return nums.size();
        }
        else
        {
            return 0;
        }
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二分查找是一种快速查找的方法,它可以在有序数组中查找指定元素的位置。首先,我们需要对数组进行初始化,即确定左右指针的初始位置。然后,利用二分法的思想,将待查找的元素与数组的中间元素进行比较。如果中间元素小于等于待查找元素,则将左指针移动到中间元素的位置。如果中间元素大于待查找元素,则将右指针移动到中间元素的位置。重复以上步骤,直到找到目标元素或者左指针等于右指针。 在Python中实现二分查找可以按照以下步骤进行: 1. 初始化左右指针为数组的边界值,即左指针为-1,右指针为数组长度。 2. 当左指针加1不等于右指针时,执行以下循环。 3. 计算中间位置m,通过将左指针与右指针之和除以2得到。 4. 若中间元素小于等于待查找元素,则将左指针移动到中间位置。 5. 若中间元素大于待查找元素,则将右指针移动到中间位置。 6. 返回右指针所在位置的元素,即为目标元素。 这是用Python实现二分查找的示例代码: ```python def binary_search(arr, key): N = len(arr) l, r = -1, N # 初始化左右指针的位置 while l + 1 != r: # 当左指针加1不等于右指针时执行循环 m = int(l + (r - l) / 2) # 计算中间位置m if arr[m <= key: # 若中间元素小于等于待查找元素 l = m # 将左指针移动到中间位置 else: r = m # 若中间元素大于待查找元素,则将右指针移动到中间位置 return arr[r # 返回右指针所在位置的元素 if __name__ == '__main__': arr = [1, 2, 3, 4, 5, 5, 5, 8, 9] key = 5 num = binary_search(arr, key) print(num) ``` 以上是关于二分查找的边界问题的Python实现方法。通过对左右指针的初始化和移动,我们可以在有序数组中快速查找指定元素的位置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [二分查找 边界查找](https://blog.csdn.net/CCSUXWZ/article/details/120771067)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Python有序查找算法之二分法实例分析](https://download.csdn.net/download/weixin_38627769/13774169)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值