首页 > 编程语言 >【oj刷题】二分查找篇:二分查找算法的原理和应用场景

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

时间:2024-09-19 19:23:45浏览次数:11  
标签:二分 right oj nums 查找 target left

前言:

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

目录

一、什么是二分查找?

二、二分查找的原理

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 };
}

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

三、总结

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

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

标签:二分,right,oj,nums,查找,target,left
From: https://blog.csdn.net/2301_80220607/article/details/142343364

相关文章

  • 简单C#递归(向前查找上工序)
    ///<summary>///递归查找前工序,直到找到没有跳序的前工序///</summary>///<paramname="process"></param>///<returns></returns>privateasyncTask<List<string>>HasReportedWorkAsync(List<WorkOrderProcedureEnti......
  • DMOJ我的三周目经验贴
    试了三遍,终于挂载成功了DMOJ,随笔记录Ubuntu20.04、Ubuntu20.04【WSL】适用官方提供的开发文档DMOJ官网GitHub地址1.环境配置aptupdate#大前置aptinstallgitgccg++makepython3-devpython3-piplibxml2-devlibxslt1-devzlib1g-devgettextcurlredis-server#n......
  • QDUOJ手动部署心得
    手动QDUOJ部署[更推荐官网一键部署,手动有失败率,但是能更深入理解部署过程]目录★标记的部分很重要一、需求环境Docker,Docker-compose,python=3.8[推荐]#查看版本docker-vdocker-compose-v环境配置[Ubuntu20.04,不推荐22原因:前端很多前置包22不支持]:#1.docker安装#......
  • 34. 在排序数组中查找元素的第一个和最后一个位置
    思路先判断target是否存在列表中,不存在直接输出存在,则找出第一个等于target值的列表位置,即目标值在列表中的开始位置接着在当前位置继续往下查找,找到最后一个目标值等于列表值的位置(也可用二分查找找到等于target值的位置+往前、往后找到开始、结束位置,但会超限,可参考(......
  • 算法设计与分析(二分查找算法
    目录二分查找算法详解引言算法步骤代码实现注意事项结论小结:二分查找算法详解引言二分查找算法是一种在有序数组中查找特定元素的搜索算法。它通过不断将数组分成两半,缩小搜索范围,从而快速定位到目标元素的位置。二分查找算法的时间复杂度为O(logn),其中n是数组的长度。算法步骤......
  • 二叉 查找 树
    目录WhyneedBinaryTree?树也是节点结构规定术语树的创建树的查找查找效率WhyneedBinaryTree?有时候,我们希望数据按照特定顺序排列。比如:想要按字母顺序排列人名;按价格顺序排列产品;...树也是节点结构规定二叉树的每个节点的子节点数量都是0、1、2;每个节点最......
  • C++ 逆向之 main 函数的查找
    在整个程序的逆向分析过程中,寻找main函数是逆向分析过程的第一步,程序的主要逻辑从这里展开。这里面涉及到两个概念:用户入口(UserEntryPoint)和应用程序入口(ApplicationEntryPoint)。用户入口用户入口是开发者编写的用于程序开始的函数。对于大多数C/C++程序而言,这个入......
  • LOJ #3490. 「JOISC 2021 Day2」逃跑路线
    Description在IOI王国,人们使用Byou作为时间单位。IOI王国中的一天被分为了\(S\)个时间单位。每天从最开始经过\(x\(0\lex<S)\)Byou后的时间称为时刻\(x\)。IOI王国由\(N\)个城市组成,以\(0\)到\(N-1\)编号。其中有\(M\)条双向道路连接某些城市,以\(0\)......
  • 南沙C++信奥老师解一本通题:1337:【例3-2】单词查找树
    ​【题目描述】在进行文法分析的时候,通常需要检测一个单词是否在我们的单词列表里。为了提高查找和定位的速度,通常都画出与单词列表所对应的单词查找树,其特点如下:1.根结点不包含字母,除根结点外每一个结点都仅包含一个大写英文字母;2.从根结点到某一结点,路径上经过的字母依次连起......
  • C#——LINQ to XML(使用 Descendants 方法查找单个子代)
    xml位于命名空间中时查找staticvoidMain(string[]args){XElementroot=XElement.Parse(@"<aw:Rootxmlns:aw='http://www.efun.com'><aw:Child1><aw:GrandChild1>GC1Value</aw:GrandChild1>&l......