【数组】二分查找(减不减一,看初始化!)

news2024/11/27 19:50:47

一、力扣习题链接

704. 二分查找 - 力扣(LeetCode)

二、思路

这道题目的前提是数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件,当大家看到题目描述满足如上条件的时候,可要想一想是不是可以用二分法了。

二分查找涉及的很多的边界条件,逻辑比较简单,但就是写不好。

例如到底是 while(left < right) 还是 while(left <= right)

到底是right = middle呢,还是要right = middle - 1呢?

大家写二分法经常写乱,主要是因为对区间的定义没有想清楚,区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。

写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)

一句秒杀:说实话,看完下面的解释我还是一团糟,但是我可以理解的是,如果如果是左闭右开,那么right就要end-1,好的,现在我更改口令:只要初始化-1,代表着父区间右侧-1,所以接下来的子区间右侧都要乖乖听话-1;如果左闭右闭,那么由于初始化不-1,所以middle就不-1;对于所有的左区间,middle通通+1!!!!

2.1左闭右闭

第一种写法,我们定义 target 是在一个在左闭右闭的区间里,也就是[left, right] 

区间的不同决定了二分法代码的不同!

  • while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=

  • if (nums[middle] > target) 的话,right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1

总结:因为这里是右闭,那么引发的俩个问题:左可等于右,把左闭右开想成原型的话,右闭多了一个元素,所以要-1

例如在数组:1,2,3,4,7,9,10中查找元素2,如图所示:

发现元素在左区间,更新right

发现元素在右区间,更新left

classs Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1; // end指向最后一个元素的下一个位置
        while (left <= right) { //  必须是<=
            int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

2.2左闭右开

如果说定义 target 是在一个在左闭右开的区间里,也就是[left, right) ,那么二分法的边界处理方式则截然不同。

有如下两点:

  • while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的

  • if (nums[middle] > target) 的话,right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]

在数组:1,2,3,4,7,9,10中查找元素2,如图所示:

// 版本二
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size(); // [left, right)
        while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) /2);
            if (nums[middle] > target) {
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

2.3distance函数

class Solution {
public:
    int search(vector<int>& nums, int target) {
      vector<int>::iterator it=find(nums.begin(),nums.end(),target);
      if(it!=nums.end())
      return distance(nums.begin(),it);
      else
      return -1;
    }
};

 三、小结

二分法是非常重要的基础算法,为什么很多同学对于二分法都是一看就会,一写就废

其实主要就是对区间的定义没有理解清楚,在循环中没有始终坚持根据查找区间的定义来做边界处理。

区间的定义就是不变量,那么在循环中坚持根据查找区间的定义来做边界处理,就是循环不变量规则。

本篇根据两种常见的区间定义,给出了两种二分法的写法,每一个边界为什么这么处理,都根据区间的定义做了详细介绍。

四、拓展练习(35,34,69,367) 

以下为题解

  • 35.搜索插入位置(opens new window)​​​​​​
  • 34.在排序数组中查找元素的第一个和最后一个位置(opens new window)
  • 69.x 的平方根(opens new window)
  • 367.有效的完全平方数(opens new window)

希望给大家带来帮助!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1070212.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

四、二叉树-下(Binary tree)

文章目录 一、算法核心二、经典例题1.[226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/description/)&#xff08;1&#xff09;思想&#xff08;2&#xff09;代码&#xff08;3&#xff09;复杂度分析 2.[101. 对称二叉树](https://leetcode.cn/problems…

【JavaSE】Synchronized实现原理

我们通常来使用synchronized来保证原子性&#xff0c;保证线程的安全。 但其实synchronized的底层是由一对monitorenter/monitorexit指令实现&#xff0c;每一个对象都有一个监视器&#xff08;monitor&#xff09;&#xff0c;而synchronized是通过对象内部叫监听器&#xff…

11.3 读图举例

一、低频功率放大电路 图11.3.1所示为实用低频功率放大电路&#xff0c;最大输出功率为 7 W 7\,\textrm W 7W。其中 A \textrm A A 的型号为 LF356N&#xff0c; T 1 T_1 T1​ 和 T 3 T_3 T3​ 的型号为 2SC1815&#xff0c; T 4 T_4 T4​ 的型号为 2SD525&#xff0c; T 2…

一款超好用的开源内存剖析器,今天教你怎么用!

Memray是一个由彭博社开发的、开源内存剖析器&#xff1b;开源一个多月&#xff0c;已经收获了超8.4k的star&#xff0c;是名副其实的明星项目。今天我们就给大家来推荐这款python内存分析神器。 Memray可以跟踪python代码、本机扩展模块和python解释器本身中内存分配&#xff…

【C++】运算符重载 ⑫ ( 等于判断 == 运算符重载 | 不等于判断 != 运算符重载 | 完整代码示例 )

文章目录 一、数组类 等号 运算符重载1、等于判断 运算符重载2、不等于判断 ! 运算符重载 二、完整代码示例1、Array.h 数组头文件2、Array.cpp 数组实现类3、Test.cpp 测试类4、执行结果 一、数组类 等号 运算符重载 1、等于判断 运算符重载 使用 成员函数 实现 等于判断 …

盒子模型的基础

盒子模型 边框&#xff08;border&#xff09; border可以设置元素的边框&#xff0c;边框分成三部分&#xff0c;边框的&#xff08;粗细&#xff09;边框的样式&#xff0c;边框的颜色 <style>div {width: 100px;height: 100px;border-width: 200;border-style: 边框…

【运行时数据区和程序计数器】

文章目录 1. 运行时数据区2. 程序计数器(PC 寄存器) 1. 运行时数据区 当我们通过前面的&#xff1a;类的加载-> 验证 -> 准备 -> 解析 -> 初始化 这几个阶段完成后&#xff0c;就会用到执行引擎对我们的类进行使用&#xff0c;同时执行引擎将会使用到我们运行时数据…

你了解的SpringCloud核心组件有哪些?他们各有什么作用?

SpringCloud 1.什么是 Spring cloud Spring Cloud 为最常见的分布式系统模式提供了一种简单且易于接受的编程模型&#xff0c;帮助开发人员构建有弹性的、可靠的、协调的应用程序。Spring Cloud 构建于 Spring Boot 之上&#xff0c;使得开发者很容易入手并快速应用于生产中。…

px4仿真实现无人机自主飞行

一,确定消息类型 无人机通过即在电脑是现自主飞行:思路如下。 通过Mavros功能包,将ROS消息转换为Mavlink消息。实现对无人机的控制。 几种消息之间的关系如下: 对于ROS数据,就是我们机载电脑执行ROS系统的数据。 对于Mavros消息,就是Mavros功能包内部的消息。查询网站…

【SkyWalking】SkyWalking是如何实现跨进程传播链路数据?

文章目录 一、简介1 为什么写这篇文章2 跨进程传播协议-简介 二、协议1 Standard Header项2 Extension Header项3 Correlation Header项 三、跨进程传播协议的源码分析1 OpenTracing规范2 通过dubbo插件分析跨进程数据传播3 分析跨进程传播协议的核心源码 四、小结参考 一、简介…

ERDAS 2022 安装教程

注意&#xff1a; 演示ERDAS版本为&#xff1a;2022.v16.7.0.1216 安装程序&#xff1a; 1、主程序&#xff1a;点击下载 2、许可文件&#xff1a;点击下载 3、IDM下载器&#xff1a;点击下载 下载速度&#xff1a; 浏览器下载速度慢&#xff0c;可以使用以上提供的IDM下…

[GWCTF 2019]我有一个数据库 phpMyAdmin 4.8.1后台文件包含漏洞

一开始打开是乱码 之前题目做过修复乱码的&#xff0c;得到这个 用dirsearch扫一下 一开始我是看到robots.txt 访问一下 访问一下phpinfo 也没啥&#xff0c;看到phpmyadimin 访问一下 没啥思路&#xff0c;看了wp 看到phpMyAdmin 4.8.1后台文件包含漏洞&#xff08;CV…

LabVIEW中不同颜色连线的含义

LabVIEW中不同颜色连线的含义 LabVIEW中的连线具有不同的颜色&#xff0c;样式和宽度。每个都代表了什么&#xff1f; 下表列出了常见的连线类型&#xff1a; 相关信息 请注意&#xff0c;类的连线颜色是可更改的。该表显示其默认外观。 连线用于在程序框图各对象间传递数据…

016 Spring Boot + Vue 图书管理系统

Spring Boot Vue 图书馆管理系统&#xff08;library-system&#xff09; 本地快捷预览项目 第一步&#xff1a;运行 db 文件夹下的springboot-vue.sql(询问作者获取)&#xff0c;创建springboot-vue数据库 第二步&#xff1a;修改后端数据库配置文件&#xff0c;启动后端 …

二次封装View Design的table组件,实现宽度自适应,内容在一行展示

由于table组件本身并不支持宽度自适应&#xff0c;但实际项目需要&#xff0c;而且多处有用到table组件&#xff0c;所以尝试着自己来二次封装一下组件 想法 刚开始的想法很简单&#xff0c;就是获取每一列中数据和标题在表格中的长度&#xff0c;然后将当中最大的长度作为该列…

Nginx配置文件的通用语法介绍

要是参考《Ubuntu 20.04使用源码安装nginx 1.14.0》安装nginx的话&#xff0c;nginx配置文件在/nginx/conf目录里边&#xff0c;/nginx/conf里边的配置文件结构如下图所示&#xff1a; nginx.conf是主配置文件&#xff0c;它是一个ascii文本文件。配置文件由指令&#xff08;…

分析“由于找不到vcruntime140.dll无法继续执行代码”这个问题的5个解决方法

当使用电脑时&#xff0c;我们难免会遇到各种问题。其中&#xff0c;“由于找不到vcruntime140.dll无法继续执行代码”是一个常见的错误&#xff0c;通常出现在运行使用C编写的应用程序时。这个问题可能会导致软件程序或游戏无法打开或运行。然而&#xff0c;只要我们掌握正确的…

大话机器学习准确率(Accuracy)、精确率(Pecision)、召回率(Recall)以及TP、FP、TN、FN

话说三国时期&#xff0c;乱世出人才&#xff0c;当时刘备让张飞帮忙招兵买马&#xff0c;寻找人才。张飞发公告以后&#xff0c;有10人来面试&#xff0c;这10人分为两类&#xff0c;人才和庸才&#xff0c;各占百分之五十&#xff0c;张飞的主要作用就是从这10人中识别出人才…

放大招,百度文心大模型4.0正在加紧训练,即将发布

插播一条快讯&#xff01; &#xfeff;&#xfeff;刚刚看到一篇报道&#xff0c;说百度正在加紧训练文心大模型4.0&#xff01;百度5月发布了文心大模型3.5&#xff0c;才4个多月又要发布4.0了&#xff0c;这迭代速度简直了。据说这次发布将在10月17日百度世界大会上进行&am…

strcat函数详解:字符串追加的利器

目录 一&#xff0c;strcat函数的简介 二&#xff0c;strcat函数的使用 三&#xff0c;strcat函数的注意事项 四&#xff0c;strcat函数的模拟实现 一&#xff0c;strcat函数的简介 strcat函数用于将源字符串追加到目标字符串的末尾&#xff0c;并返回一个指向目标字符串的…