当前位置: 首页 > article >正文

【oj刷题】二分查找篇:二分查找算法的原理和应用场景

前言:

二分查找算法,又称折半查找算法,是一种在有序数组中查找特定元素的高效查找方法。它通过将搜索区间不断缩小一半,从而在对数时间内找到目标元素。二分查找是基于分治策略的一种典型应用,能够高效的处理许多问题,下面我们就来看一下二分查找算法的原理和应用场景

目录

一、什么是二分查找?

二、二分查找的原理

2.1 朴素二分模板

2.2 查找区间左右端点的模板

三、总结


一、什么是二分查找?

二分查找一般是基于有序数组的,通过比较目标值与中间元素的大小关系,来决定是在数组的左侧还是右侧继续搜索。

我们就拿有序数组来做例子,具体步骤如下:

  1. 初始化:确定查找的起始位置(left)和结束位置(right)。
  2. 循环条件:当left小于等于right时,继续查找。
  3. 查找中间元素:计算mid =left+(right-left)/2,这是当前搜索区间内的中间位置。
  4. 比较与调整
    • 如果中间元素等于目标值,则查找成功,返回中间元素的索引。
    • 如果中间元素小于目标值,则目标值可能在中间元素的右侧,因此将left更新为mid + 1
    • 如果中间元素大于目标值,则目标值可能在中间元素的左侧,因此将right更新为mid - 1
  5. 查找失败:如果循环结束仍未找到目标值,说明目标值不在数组中,返回特定值表示查找失败(通常返回-1或null)。

二、二分查找的原理

二分查找我们可以分为三个模板:

1、朴素的二分模板

2、查找左边界的二分模板

3、查找右边界的二分模板

2.1 朴素二分模板

朴素二分模板我们可以拿下面这题来举个例子:

力扣704 二分查找

给定一个 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

提示:

  1. 你可以假设 nums 中的所有元素是不重复的。
  2. n 将在 [1, 10000]之间。
  3. nums 的每个元素都将在 [-9999, 9999]之间。

算法原理:

代码实现:

int search(vector<int>& nums, int target) {
    int left = 0, right = nums.size() - 1;
    while (left <= right)
    {
        int mid = left + (right - left) / 2;    //防止溢出
        if (nums[mid] > target) right = mid - 1;
        else if (nums[mid] < target) left = mid + 1;
        else return mid;
    }
    return -1;
}

2.2 查找区间左右端点的模板

我们也通过一道例题来讲解这个模板:

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

提示:

  • 0 <= nums.length <= 105
  • -10^9 <= nums[i] <= 10^9
  • nums 是一个非递减数组
  • -10^9 <= target <= 10^9

算法原理:

在这道题中我们可以很清楚的看到这道题用朴素二分查找是不能够解决问题的,因为朴素二分查找是用来找一个目标值,但是这道题则是求一个区间范围,所以这里就引出了一个新的模板——查找区间左右断点的模板,下面我们就来看一下这个模板的原理:

1、先来看一下如何找左端点

2、右端点的找法与左端点很相似,最大的区别就是在找中间端点时和移动left和right时有所不同:

代码实现:

vector<int> searchRange(vector<int>& nums, int target) {
    if (nums.size() == 0)
        return { -1, -1 }; // 判断数组为空的情况
    int begin = 0, end = 0;
    // 1.二分左端点
    int left = 0, right = nums.size() - 1;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target)
            left = mid + 1;
        else
            right = mid;
    }
    if (nums[left] != target)
        return { -1, -1 };
    else
        begin = left;
    // 2.二分右端点
    left = 0, right = nums.size() - 1;
    while (left < right) {
        int mid = left + (right - left + 1) / 2;
        if (nums[mid] > target)
            right = mid - 1;
        else
            left = mid;
    }
    if (nums[right] != target)
        return { -1, -1 };
    else
        end = right;
    return { begin, end };
}

上面的就是二分查找的模板,我们平时做题时就可以判断是哪种类型的直接套模板,但是每个题都有各自的细节点,所以写的时候也要注意一下细节

三、总结

以上就是二分查找算法的原理和应用场景,其中讲到的模板是具有通行的,在很多场景下稍作更改就可以使用

感谢各位大佬观看,创作不易,还望各位大佬点赞支持!!!


http://www.kler.cn/news/310253.html

相关文章:

  • 滤波器的分类
  • PM2.5粉尘传感器详解(STM32)
  • 记录一下ElementUI 3 在浏览器导入, table表格显示问题
  • 笔记:简介Drawing是什么,都有哪些,如何使用
  • 前后端联调
  • 如何建立一个Webservice WSDL的简单例子(完整例子)
  • 如何在微信小程序中实现WebSocket连接
  • JEE 设计模式
  • 黑神话悟空mac可以玩吗
  • 软考高级:嵌入式系统调度算法 AI 解读
  • OJ 组合总和
  • MySQL面试题--连续三天登录(困难)
  • Python基础(七)——PyEcharts数据分析(面向对象版)
  • fortran定义数组
  • [SAP ABAP] 修改内表数据
  • HDMI色块移动——FPGA学习笔记13
  • VulhubDC-4靶机详解
  • Linux系统性能调优技巧详解
  • 『功能项目』回调函数处理死亡【54】
  • docker基础学习
  • C++调用C# DLL之踩坑记录
  • Oracle 数据库安装和配置教程
  • 每日学习一个数据结构-红黑树
  • 电脑怎么录屏?四款录屏工具分享
  • C++ | Leetcode C++题解之第416题分割等和子集
  • python简单易懂的lxml读取HTML节点及常用操作方法
  • 前端大模型入门:掌握langchain的核心Runnable接口(一)
  • 全面升级!最新版抖音蓝V商家采集软件,海量资源一网打尽
  • redis集群常用命令梳理
  • 高级java每日一道面试题-2024年9月17日-框架篇-什么是ORM框架?