高效查找:二分查找算法解析

1.二分查找简介

二分查找算法(Binary Search)是一种高效的查找算法,适用于有序数组或序列。它的基本思想是通过逐步缩小查找范围,将查找区间一分为二,直到找到目标值或确定目标值不存在。

算法原理:在数组的中间位置选择一个元素作为“中间值”。将目标值与“中间值”进行比较:如果目标值等于中间值,查找成功,返回中间值的索引。如果目标值小于中间值,则在左半部分继续查找。如果目标值大于中间值,则在右半部分继续查找。重复以上步骤,直到找到目标值或区间为空(即找不到目标值)。

时间复杂度:二分查找的时间复杂度为 (O(\log n)),其中 (n) 是数组的元素个数。每次查找将查找范围缩小一半,因而效率较高。

在二分查找中,针对特定需求,常用的有以下三种方式:

(1)朴素二分查找:查找任意一个等于目标值的位置。

朴素二分查找模版

while (left <= right)//循环条件
{int mid = left + (right - left) / 2;//left + (right - left + 1) / 2也可if (...) left = mid + 1;else if (...) right = mid - 1;elsereturn ...}

(2)左端点二分查找:查找目标值的最左位置(即第一个出现的目标值)。

二分查找区间左端点

while (left < right)//判断条件不能等于
{int mid = left + (right - left) / 2;//只能是left + (right - left) / 2if (...) left = mid + 1;else right = mid;
}

(3)右端点二分查找:查找目标值的最右位置(即最后一个出现的目标值)。 

二分查找区间右端点

        //找右端点while (left < right)//判断条件不能等于{int mid = left + (right - left + 1) / 2;//只能是left + (right - left + 1) / 2if (...) left = mid;else right = mid - 1;}

二分查找不仅适用于有序数组,还适用于具有二段性的情况。二段性指的是一个序列被划分成两段:在某个位置之前满足某个条件,而在该位置之后不满足(或反之)。利用二分查找,能够高效地找到这个转折点。 

2.二分查找

1. 题目简介

2. 算法思想

暴力解法:遍历数组寻找目标值

二分查找:数组是升序的

(1)循环结束条件:left <= right

(2)中间值小于目标值,去右区间查找:mid < target  ->  left = mid + 1

中间值大于目标值,去左区间查找:mid > target  ->  right = mid - 1

中间值等于目标值:返回

3. 代码实现

class Solution {
public: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) left = mid + 1;else if (nums[mid] > target) right = mid - 1;else if (nums[mid] == target) return mid;}return -1;}
};

. - 力扣(LeetCode)

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

1. 题目简介

2. 算法思想

暴力解法:遍历数组,找到符合条件的区间

二分查找:有序数组,可以用二分查找,使用左右端点二分查找找到符合条件的区间的左右端点

(1)循环结束条件:left < right 

(2)找左端点

中间值小于目标值,找大:mid < target  ->  left = mid + 1

中间值大于目标值,找小:mid >= target  ->  right = mid

(3)找右端点

中间值小于目标值,找大:mid <= target  ->  left = mid

中间值大于目标值,找小:mid > target  ->  right = mid - 1

3. 代码实现

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

. - 力扣(LeetCode)

4. x的平安根

1. 题目简介

2. 算法思想

暴力解法:从1开始计算其平方,找到第一个平方大于target的数

二分查找:从1开始到x区间使用二分查找法,返回值左区间的元素平方小于等于x,右区间元素平方大于x。

(1)循环结束条件:left < right

(2)小于目标值,找大:mid * mid <= x  ->  left = mid 

大于目标值,找小:mid * mid > x  ->  right = mid - 1

3. 代码实现

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

. - 力扣(LeetCode)

5. 搜索插入位置

1. 题目简介

2. 算法思想

暴力解法:遍历数组找到第一个比目标值大的元素的下标

二分查找:数组是升序的,我们要找的返回值是大于等于target的,因此将数组分为左右两个区间,左边区间小于target,右边区间大于等于target,,所以我们要找到右区间的左端点。

(1)循环结束条件:left < right

(2)中间值小于目标值,则应该找大:mid < target  ->  left = mid + 1

中间值大于目标值,找小:mid > target  ->  right = mid

class Solution {
public:int searchInsert(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) left = mid + 1;else right = mid; }if (nums[left] < target) return left + 1;else return left;}
};

. - 力扣(LeetCode)

6. 山脉数组的封顶索引

1. 题目简介

暴力解法:遍历数组寻找峰值

二分查找:数组具有二段性,arr[i] < arr[i + 1],arr[i] > arr[i+ 1]

(1)循环结束条件:left < right

(2)处于升序部分:arr[mid] >= arr[mid - 1] left = mid;   

处于降序部分:arr[mid] < arr[mid - 1] right = mid - 1;

3. 代码实现

class Solution {
public:int peakIndexInMountainArray(vector<int>& arr) {int left = 1, right = arr.size() - 2;while (left < right){int mid = left + (right - left + 1) / 2;if (arr[mid] >= arr[mid - 1]) left = mid;else right = mid - 1;}return left;}
};

. - 力扣(LeetCode)

7. 寻找峰值

1. 题目简介

2. 算法思想

3. 代码实现

暴力解法:遍历数组,找到一个大于左右相邻值的元素

二分查找算法:找二段性,nums[-1] = nums[n] = -∞,arr[i] > arr[i + 1] 则左边一定存在峰值,

arr[i] < arr[i + 1] 则右边一定存在峰值。

(1)循环结束条件: left < right

(2)处于递减序列中:nums[mid] > nums[mid + 1] -> right = mid;

处于递增序列中:nums[mid] <= nums[mid + 1] -> left = mid + 1

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

8.搜索旋转排序数组中的最小值

1. 题目简介

2. 算法思想

暴力解法:遍历数组找到最小值

二分查找:找二段性,AB之间大于数组最后一个元素,CD之间小于等于D元素

(1)循环条件:left < right

(2)中间值大于D:left = mid + 1

中间值小于等于D:right = mid

 3. 代码实现

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

. - 力扣(LeetCode)

9. 0〜n-1 中缺失的数字

1. 题目简介

2. 算法思想

暴力解法:遍历数组,时间复杂度为O(n)

二分查找:找二段性,目标元素左边区间的元素和它们的下标相等,右边区间的元素比他们的下标大1

(1)循环结束条件:left < right

(2) 元素和下标相等:records[mid] == mid -> left = mid + 1;

不相等:right = mid;

3. 代码实现

class Solution {
public:int takeAttendance(vector<int>& records) {int left = 0, right = records.size() - 1;while (left < right){int mid = left + (right - left) / 2;if (records[mid] == mid) left = mid + 1;else right = mid;}if (records[left] == left) return left + 1;else return left;}
};

. - 力扣(LeetCode)

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

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

相关文章

数据统计–图形报表(day11)

Apache ECharts 介绍 Apache ECharts 介绍 Apache ECharts 是一款基于 Javascript 的数据可视化图表库&#xff0c;提供直观&#xff0c;生动&#xff0c;可交互&#xff0c;可个性化定制的数据可视化图表。 官网地址&#xff1a;Apache ECharts 入门案例 Apache Echarts官方…

Docker可视化管理工具Portainer

Portainer简介 Portainer 是一个轻量级的、开源的容器管理工具&#xff0c;提供了一个直观的 Web 用户界面&#xff08;UI&#xff09;&#xff0c;用于管理 Docker 和 Kubernetes 环境。它简化了容器的部署、监控和管理&#xff0c;特别适合不熟悉命令行操作的用户或团队。 …

C++入门14——set与map的使用

在本专栏的往期文章中&#xff0c;我们已经学习了STL的部分容器&#xff0c;如vector、list、stack、queue等&#xff0c;这些容器统称为序列式容器&#xff0c;因为其底层是线性序列的数据结构&#xff0c;里面存储的是元素本身。而本篇文章我们要来认识一下关联式容器。 &am…

浅析云场景SSD实时迁移技术

在数据中心的运营管理中&#xff0c;负载均衡和系统容错是确保高效稳定运行的关键。SSD实时迁移技术&#xff0c;为解决这些问题提供了创新方案&#xff0c;成为数据中心技术发展的重要驱动力。 以AI训练任务为例&#xff0c;其运行时间长且无需用户频繁交互。数据中心的负载会…

同一局域网远程控制其他电脑以及Windows家庭版开启远程桌面等解决方法

1. 前言 家庭版的 Windows 10 和 Windows 11 默认不支持远程桌面功能。然而&#xff0c;我们可以通过使用 RDPWrap 项目来启用这一功能。 电脑的“设置”-> “远程桌面设置”中查看系统是否支持远程桌面 2.下载安装 RDPWrap 安装该项目使家庭版也支持远程桌面 项目地址&…

DeepSeek-R1:将强化学习用于激励大型语言模型的推理能力

目录 引言 一、DeepSeek-R1的贡献 二、DeepSeek-R1的方法 2.1、DeepSeek-R1-Zero&#xff1a;基础模型上的强化学习 2.2、DeepSeek-R1&#xff1a;冷启动强化学习 2.3、蒸馏&#xff1a;赋予小模型推理能力 三、DeepSeek-R1实验结果 3.1、模型优点 3.2、模型缺点 四、…

数据库管理-第287期 Oracle DB 23.7新特性一览(20250124)

数据库管理287期 20245-01-24 数据库管理-第287期 Oracle DB 23.7新特性一览&#xff08;20250124&#xff09;1 AI向量搜索&#xff1a;算术和聚合运算2 更改Compatible至23.6.0&#xff0c;以使用23.6或更高版本中的新AI向量搜索功能3 Cloud Developer包4 DBMS_DEVELOPER.GET…

Android BitmapShader简洁实现马赛克,Kotlin(二)

Android BitmapShader简洁实现马赛克&#xff0c;Kotlin&#xff08;二&#xff09; 这一篇 Android BitmapShader简洁实现马赛克&#xff0c;Kotlin&#xff08;一&#xff09;-CSDN博客 遗留一个问题&#xff0c;xml定义的MyView为wrap_content的宽高&#xff0c;如果改成其…

智能化加速标准和协议的更新并推动验证IP(VIP)在芯片设计中的更广泛应用

作者&#xff1a;Karthik Gopal, SmartDV Technologies亚洲区总经理 智权半导体科技&#xff08;厦门&#xff09;有限公司总经理 随着AI技术向边缘和端侧设备广泛渗透&#xff0c;芯片设计师不仅需要考虑在其设计中引入加速器&#xff0c;也在考虑采用速度更快和带宽更高的总…

【问题】Chrome安装不受支持的扩展 解决方案

此扩展程序已停用&#xff0c;因为它已不再受支持 Chromium 建议您移除它。详细了解受支持的扩展程序 此扩展程序已停用&#xff0c;因为它已不再受支持 详情移除 解决 1. 解压扩展 2.打开manifest.json 3.修改版本 将 manifest_version 改为3及以上 {"manifest_ver…

Vue入门(Vue基本语法、axios、组件、事件分发)

Vue入门 Vue概述 Vue (读音/vju/&#xff0c;类似于view)是一套用于构建用户界面的渐进式框架&#xff0c;发布于2014年2月。与其它大型框架不同的是&#xff0c;Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三…

[云讷科技]Kerloud Falcon四旋翼飞车虚拟仿真空间发布

虚拟仿真环境作为一个独立的专有软件包提供给我们的客户&#xff0c;用于帮助用户在实际测试之前验证自身的代码&#xff0c;并通过在仿真引擎中添加新的场景来探索新的飞行驾驶功能。 环境要求 由于环境依赖关系&#xff0c;虚拟仿真只能运行在装有Ubuntu 18.04的Intel-64位…

postgresql15的启动

PostgreSQL是一个功能非常强大的、源代码开放的客户/服务器关系型数据库管理系统&#xff0c;且因为许可证的灵活&#xff0c;任何人都可以以任何目的免费使用、修改和分发PostgreSQL。现在国产数据库大力发展阶段&#xff0c;学习和熟悉postgresql的功能是非常有必要的&#x…

Python NumPy(1):介绍、Ndarray对象、NumPy数据类型

1 介绍 NumPy(Numerical Python) 是 Python 语言的一个扩展程序库&#xff0c;支持大量的维度数组与矩阵运算&#xff0c;此外也针对数组运算提供大量的数学函数库。NumPy 是一个运行速度非常快的数学库&#xff0c;主要用于数组计算&#xff0c;包含&#xff1a; 一个强大的N…

sql语句--新手入门增删改查保姆级教学

一丶在数据库管理系统中&#xff0c;SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;是用于访问和操作数据库的标准编程语言。以下将通过一个假设的“articles”表&#xff08;代表文章或博客条目&#xff09;来展示SQL中的增&#xff08;Ins…

INCOSE需求编写指南-第1部分:介绍

第1部分&#xff1a;介绍Section 1: Introduction 1.1 目的和范围 Purpose and Scope 本指南专门介绍如何在系统工程背景下以文本形式表达需求和要求陈述。其目的是将现有标准&#xff08;如 ISO/IEC/IEEE 29148&#xff09;中的建议以及作者、主要贡献者和审稿员的最佳实践结…

Windows上通过Git Bash激活Anaconda

在Windows上配置完Anaconda后&#xff0c;普遍通过Anaconda Prompt激活虚拟环境并执行Python&#xff0c;如下图所示&#xff1a; 有时需要连续执行多个python脚本时&#xff0c;直接在Anaconda Prompt下可以通过在以下方式&#xff0c;即命令间通过&&连接&#xff0c;…

GIS 中的 SQLAlchemy:空间数据与数据库之间的桥梁

利用 SQLAlchemy 在现代应用程序中无缝集成地理空间数据导言 地理信息系统&#xff08;GIS&#xff09;在管理城市规划、环境监测和导航系统等各种应用的空间数据方面发挥着至关重要的作用。虽然 PostGIS 或 SpatiaLite 等专业地理空间数据库在处理空间数据方面非常出色&#…

MySQL中的读锁与写锁:概念与作用深度剖析

MySQL中的读锁与写锁&#xff1a;概念与作用深度剖析 在MySQL数据库的并发控制机制中&#xff0c;读锁和写锁起着至关重要的作用。它们是确保数据在多用户环境下能够正确、安全地被访问和修改的关键工具。 一、读锁&#xff08;共享锁&#xff09;概念 读锁&#xff0c;也称为…

SpringBoot 实现动态管理定时任务 Job的动态操作(添加、修改、启停、执行、删除)以及界面展示和具体Job的创建与执行示例

SpringBoot 实现动态管理定时任务 Job的动态操作&#xff08;添加、修改、启停、执行、删除&#xff09;以及界面展示和具体Job的创建与执行示例 关键接口类&#xff1a; CronTaskRegistrar SchedulingRunnable . 添加定时任务注册类&#xff0c;用来增加、删除定时任务 impo…