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

基础算法--二分查找

什么是二分查找

二分查找,也叫折半查找,是一种专门为有序数组量身定制的查找算法。想象一下,你走进了一家按编号顺序排列书籍的图书馆,要找某一本书,要是从第一本开始逐本翻找,那可得费不少时间。二分查找可就机灵多了,它先把书架一分为二,看看目标书籍在左边还是右边,然后果断舍弃不需要的那半边,接着在剩下的半边里继续对半分、再找,如此循环,快速锁定目标。

二分查找的魅力所在

二分查找最大的优势就是效率高,它的时间复杂度是O(logN) 。啥意思呢?就是随着数据量 n 不断增大,查找所需的时间增长得极为缓慢。与之相比,顺序查找的时间复杂度是O(N) ,数据量一大,顺序查找耗时就会蹭蹭往上涨。打个比方,在有 100 万本书的图书馆里找书,二分查找可能几十次对比就搞定,顺序查找说不定就得翻个几十万次。

一道简单的题目示例

1.二分查找

 

 代码:

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

 2.在排序数组中查找元素的第⼀个和最后⼀个位置(medium)

 这里也是用二分查找,只不过这里需要查找两个端点。

首先当我们查找左端点的时候,需要处理好细节,尤其是这里求中点的操作。必须是left+(right-left)/2,因为其实left = right的时候已经是最终结果了,走到最后情况就是两个数里面找中点,因为我们是找左端点mid会落到right的位置,如果这个时候mid也落在x>=t,那么right= mid,我们会发现right没有动,那么接下来就会进入死循环。但是当我们走left+(right-left)/2的时候,mid = left,无论是x<t还是x>=t都不会进入死循环,当x<t时,left = mid+1,这时就撞上了right停止循环,当x>=t时,right就更新为mid,这时会撞上left,也会停止循环。

那么右端点也同理,必须使用mid = left+(left-right+1)/2 ,当区间内还剩两个数时,mid当时必然会落在左边的数上,如果用第一个算,那么此时mid = left,如果这时x<=t的,则left又是等于mid,则left不变,这样就会进入死循环。

这里如果我们使用mid = left+(left-right+1)/2就不会进入死循环,因为这个时候mid会等于right,那么这个时候无论是走x<=t还是x>t都不会死循环,当x<=t的时候,更新left,left = mid,撞上right,循环截止,当x>t的时候,更新right,right = mid-1,right会撞上left,循环截止。

代码:

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.size()==0) return {-1,-1};
        int begin = 0,end = 0;
        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;

        //二分右端点
        right = nums.size()-1;
        while(left<right)
        {
            int mid = left+(right-left+1)/2;
            if(nums[mid]>target) right = mid-1;
            else left = mid;
        }
        return {begin,right};
    }   
};

总结二分模板:

3.x的平⽅根(easy) 

题目非常的简单,但我们这里主要是学习使用二分查找,暴力解法也很容易想到,就是将0-x的所有数字平方遍历一遍。但我们这里要使用的是二分查找。

首先找一下二段性 ,直接看下图,ret就是要返回的目标值,ret的左边的平方一定是小于等于x的,4包含4左边的平方一定是小于17的,6的左边包含它自己会小于等于36。

那么这里就可以直接套用我们上一题总结的模板了:
 

class Solution {
public:
    int mySqrt(int x) {
        if(x<1) return 0;
        int left = 1,right = x;
        while(left<right)
        {
            long long mid = left+(right-left+1)/2;//防溢出
            if(mid*mid<=x)
            {
                left = mid;
            }
            else
            {
                right = mid-1;
            }
        }
        return right;
    }
};


http://www.kler.cn/a/543799.html

相关文章:

  • FlinkCDC 实现 MySQL 数据变更实时同步
  • Flutter PIP 插件 ---- iOS Video Call
  • 使用 SDKMAN! 在 Mac(包括 ARM 架构的 M1/M2 芯片)安装适配 Java 8 的 Maven
  • Python实现GO鹅优化算法优化支持向量机SVM分类模型项目实战
  • 单例模式详解(Java)
  • Deepseek 接入Word处理对话框(隐藏密钥)
  • Zabbix7.0服务器在告警发生时自动调用客户机脚本
  • 从零开始学Python爬虫:(二)使用基本库urllib(上)
  • Vue的scoped原理是什么
  • 在 Navicat 17 中扩展 PostgreSQL 数据类型 - 范围类型
  • NLP深度学习 DAY7:平滑、语境学习、Scaling Law、大模型的发展、LLM的构建流程
  • 【Java】详细讲解数据类型与运算符
  • PlantUML 总结
  • 使用 EDOT 监测由 OpenAI 提供支持的 Python、Node.js 和 Java 应用程序
  • Ubuntu 上安装 Elasticsearch 7.6.0
  • ubuntu22.04可视化界面
  • 如何在Excel和WPS中进行翻译
  • Java 后端开发工程师进阶路线
  • Android10 音频参数导出合并
  • 机器学习核心算法解析
  • QT 5.15.2 开发地图ArcGIS 100.15.6(ArcGIS Runtime SDK for Qt)
  • Java8新特性Optional,Function,Supplier,Consumer
  • 【Cocos TypeScript 零基础 15.1】
  • Jenkins 部署 之 Mac 一
  • ASP.NET Core SignalR实践指南
  • 如何在Java EE中使用标签库?