力扣 | 二分查找模板

在这里插入图片描述在这里插入图片描述

力扣:二分查找

文章目录

  • 📚二分查找
  • 📚模板I
    • 👉x 的平方根
    • 👉猜数字大小
    • 👉搜索旋转排序数组
  • 📚模板II
    • 👉第一个错误的版本
    • 👉寻找峰值
  • 📚模板III
    • 👉在排序数组中查找元素的第一个和最后一个位置
    • 👉找到 K 个最接近的元素❓
  • 📚模板小结

📚二分查找

  • 在最简单的形式中,二分查找对具有指定左索引和右索引的连续序列进行操作。这就是所谓的查找空间。
  • 二分查找维护查找空间的左、右和中间指示符,并比较查找目标或将查找条件应用于集合的中间值;
  • 如果条件不满足或值不相等,则清除目标不可能存在的那一半,并在剩下的一半上继续查找,直到成功为止。
  • 如果查以空的一半结束,则无法满足条件,并且无法找到目标。

📚模板I

int binarySearch(vector<int>& nums, int target)
{if(nums.size() == 0)return -1;int left = 0, right = nums.size() - 1;while(left <= right){// Prevent (left + right) overflowint mid = left + (right - left) / 2;if(nums[mid] == target){ return mid; }else if(nums[mid] < target) { left = mid + 1; }else { right = mid - 1; }}// End Condition: left > rightreturn -1;
}
  • 二分查找的最基础和最基本的形式。
  • 查找条件可以在不与元素的两侧进行比较的情况下确定(或使用它周围的特定元素)。
  • 不需要后处理,因为每一步中,你都在检查是否找到了元素。如果到达末尾,则知道未找到该元素。
    在这里插入图片描述

在这里插入图片描述

👉x 的平方根

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

在这里插入图片描述

👉猜数字大小

/** * Forward declaration of guess API.* @param  num   your guess* @return 	     -1 if num is higher than the picked number*			      1 if num is lower than the picked number*               otherwise return 0* int guess(int num);*/class Solution {
public:int guessNumber(int n) {int left=0,right=n;int mid,flag;while(left<=right){mid=left+(right-left)/2;flag=guess(mid);if(flag==1){left=mid+1;}else if(flag==-1){right=mid-1;}else{return mid;}}return -1;}
};

在这里插入图片描述

👉搜索旋转排序数组

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)return mid;else if(nums[left]<=nums[mid]){//如果中间位置的元素大于或等于左边界的元素,说明左半部分是有序的。//此时,再判断目标元素是否处于左半部分的有序区间内。if(target<nums[mid]&&target>=nums[left])right=mid-1;elseleft=mid+1;}else{//如果中间位置的元素小于左边界的元素,说明右半部分是有序的。//此时,再判断目标元素是否处于右半部分的有序区间内。if(target<=nums[right]&&target>nums[mid])left=mid+1;elseright=mid-1;}}return -1;}
};

在这里插入图片描述

📚模板II

int binarySearch(vector<int>& nums, int target){if(nums.size() == 0)return -1;int left = 0, right = nums.size();while(left < right){// Prevent (left + right) overflowint mid = left + (right - left) / 2;if(nums[mid] == target){ return mid; }else if(nums[mid] < target) { left = mid + 1; }else { right = mid; }}// Post-processing:// End Condition: left == rightif(left != nums.size() && nums[left] == target) return left;return -1;
}
  • 一种实现二分查找的高级方法。
  • 查找条件需要访问元素的直接右邻居
  • 使用元素的右邻居来确定是否满足条件,并决定是向左还是向右。
  • 保证查找空间在每一步中至少有 2 个元素。
  • 需要进行后处理。 当你剩下 1 个元素时,循环 / 递归结束。 需要评估剩余元素是否符合条件。

在这里插入图片描述

👉第一个错误的版本

// The API isBadVersion is defined for you.
// bool isBadVersion(int version);class Solution {
public:int firstBadVersion(int n) {int left=1;int right=n;while(left<right) {int mid=left+(right-left)/2;if(isBadVersion(mid)) {right=mid;} else {left=mid+1;}}return left;}
};

在这里插入图片描述

👉寻找峰值

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

在这里插入图片描述

📚模板III

int binarySearch(vector<int>& nums, int target){if (nums.size() == 0)return -1;int left = 0, right = nums.size() - 1;while (left + 1 < right){// Prevent (left + right) overflowint mid = left + (right - left) / 2;if (nums[mid] == target) {return mid;} else if (nums[mid] < target) {left = mid;} else {right = mid;}}// Post-processing:// End Condition: left + 1 == rightif(nums[left] == target) return left;if(nums[right] == target) return right;return -1;
}
  • 实现二分查找的另一种方法。
  • 搜索条件需要访问元素的直接左右邻居。
  • 使用元素的邻居来确定它是向右还是向左。
  • 保证查找空间在每个步骤中至少有 3 个元素。
  • 需要进行后处理。 当剩下 2 个元素时,循环 / 递归结束。 需要评估其余元素是否符合条件。

在这里插入图片描述


关于这所谓的三个模板,其实就分别对应三种区间的写法

//作者:Jungle8884
//链接:https://leetcode.cn/leetbook/read/binary-search/xe22ch/?discussion=hqOQPt
//来源:力扣(LeetCode)
// 二分查找 --- [left, right]// 数组已经是有序的了!public static int binarySerach1(int[] nums, int target) {if (nums == null || nums.length == 0) {return -1;}int left = 0, right = nums.length-1;while (left <= right) {// 防止溢出 等同于(left + right)/2int mid = left + (right-left)/2;if (nums[mid] == target) {return mid;} else if (nums[mid] > target) {// target 在左区间,所以[left, middle - 1]right = mid-1;} else {// target 在右区间,所以[middle + 1, right]left = mid+1;}}return -1;}// 二分查找 --- [left, right)// 数组已经是有序的了!int binarySearch2(int[] nums, int target){if(nums == null || nums.length == 0)return -1;// 定义target在左闭右开的区间里,即:[left, right)int left = 0, right = nums.length;// 因为left == right的时候,在[left, right)是无效的空间,所以使用 <while(left < right){int mid = left + (right - left) / 2;if(nums[mid] == target){return mid;}else if(nums[mid] < target) {//  target 在右区间,在[middle + 1, right)中left = mid + 1;}else {// target 在左区间,在[left, middle)中right = mid;}}// Post-processing:// End Condition: left == rightif(left != nums.length && nums[left] == target) return left;return -1;}// 二分查找 --- (left, right)// 数组已经是有序的了!int binarySearch3(int[] nums, int target) {if (nums == null || nums.length == 0)return -1;int left = 0, right = nums.length - 1;while (left + 1 < right){int mid = left + (right - left) / 2;if (nums[mid] == target) {return mid;} else if (nums[mid] < target) {//  target 在右区间,在(middle, right)中left = mid;} else {// target 在左区间,在(left, middle)中right = mid;}}// Post-processing:// End Condition: left + 1 == rightif(nums[left] == target) return left;if(nums[right] == target) return right;return -1;}

👉在排序数组中查找元素的第一个和最后一个位置

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {if(nums.size()==1){//如果数组只有1个元素if(nums[0]==target) return vector<int>{0,0}; //判断该元素是否等于目标值else return vector<int>{-1,-1};}//用两次二分,这里用的是模板IIvector<int> res={-1,-1}; //存储结果,初始化为{-1,-1}int left=0;int right=nums.size()-1;while(left<=right) {//第一次二分查找,寻找左目标值int mid=left+(right-left)/2;if(nums[mid]==target) { res[0]=mid; right=mid-1;}else if(nums[mid]>target) { right=mid-1;}else{ left=mid+1;}}left=0;right=nums.size()-1;while(left<=right){//第二次二分查找,寻找右目标值int mid=left+(right-left)/2; if(nums[mid]==target) { res[1]=mid; left=mid+1;}else if(nums[mid]>target) { right=mid-1; }else{left=mid+1; }}return res; }
};

在这里插入图片描述

👉找到 K 个最接近的元素❓

参考讨论区
在这里插入图片描述

class Solution {
public:vector<int> findClosestElements(vector<int>& arr, int k, int x) {vector<int> res;int left=0; int right=arr.size()-1;for(int i=0;i<arr.size()-k;i++){//如果左指针所指元素与x的差值小于等于右指针所指元素与x的差值,则将右指针向左移动一位if(abs(x-arr[left])<=abs(arr[right]-x)) right--; else left++; //否则将左指针向右移动一位}for(int i=left;i<=right;i++) //将左指针到右指针之间的元素加入结果数组res.push_back(arr[i]);return res;}
};

在这里插入图片描述

📚模板小结

在这里插入图片描述

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

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

相关文章

JSP+MySql实战

0目录 JSPMySql实战 创建maven工程和包 创建2张表 User表 Employee表 实体类封装 Util 包BaseDao类 Dao包 EmployeeDao类 UserDao类 实现接口方法 Dao包新建impl包 UserDaoImp EmployeeDaoImpl 新建Service包 接口方法 UserService EmployeeSe…

qt 聊天室

服务器端 widget.cpp #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this);//实例化一个服务器对象server new QTcpServer(this);}Widget::~Widget() {delete ui; }…

nginx添加模块fastdfs-nginx-module(docker版,不需要重写dockerfile)

nginx添加模块fastdfs-nginx-module&#xff08;docker版&#xff0c;不需要重写dockerfile&#xff09; 一、fastdfs-nginx-module模块准备1.1、下载模块1.2、配置模块参数 二、重新制作nginx的二进制执行文件2.1、查看nginx版本2.2、下载nginx配套版本的源码文件2.3、制作ngi…

安装RabbitMQ 详细步骤

我这里是在Linux系统里面安装的按照步骤即可 1. 安装Socat&#x1f349; 在线安装依赖环境&#xff1a; yum install gcc yum install socat yum install openssl yum install openssl-devel2. 安装Erlang&#x1f349; 去官网下载一下安装包&#xff0c;将安装包拉到Linux系…

Visual Studio Code 编辑器实用插件简介

Visual Studio Code 编辑器插件 以下是一些常用的 Visual Studio Code 编辑器插件及其简短描述&#xff1a; 2gua.rainbow-brackets&#xff1a;在括号周围添加彩虹色的边框&#xff0c;以帮助区分不同层次的括号。adpyke.codesnap&#xff1a;将代码片段转换为漂亮的图片&am…

Vue插槽

默认插槽 src/App.vue <template><div class"container"><Category title"美食"><img src"https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt""></Category><Category title"游戏">&l…

得物自建 DTS 平台的技术演进 | 精选

0 前言 DTS是数据传输平台(Data Transfer Platform的缩写) 随着得物App的用户流量增长&#xff0c;业务选择的数据库越来越多样化&#xff0c;异构数据源之间的数据同步需求也逐渐增多。为了控制成本并更好地支持业务发展&#xff0c;我们决定自建DTS平台。本文主要从技术选型、…

两组表单看懂MySQL的多表查询

第一组表单信息 1、查询每个部门的所属员工 mysql> SELECT name,GROUP_CONCAT(ename) persons-> FROM dept3 d-> LEFT JOIN emp3 e-> ON d.deptno e.dept_id-> GROUP BY d.deptno-> UNION -> SELECT name,GROUP_CONCAT(ename) persons-> FROM dept3 …

分层解耦-IOCDI引入

目录 分层解耦 如何解除耦合 控制反转&#xff08;IOC&#xff09; 依赖注入&#xff08;DI&#xff09; Bean对象 分层解耦 内聚&#xff1a;软件中各个功能模块内部的功能联系耦合&#xff1a;衡量软件中各个层/模块之间的依赖、关联程度软件设计原则&#xff1a;高内聚…

开源Cillium项目为容器提供强大的网络功能

试验性的开源Cillium项目使用Linux内核的一项现有特性&#xff0c;为容器提供高速、强大的网络功能。一项名为Cilium的开源项目试图基于Linux内核中所用的技术&#xff0c;为容器提供一种新的网络方法。 试验性的开源Cillium项目使用Linux内核的一项现有特性&#xff0c;为容器…

HP Laser 136nw打印机与win10实现Wifi直连

HP Laser 136nw打印机与win10实现Wifi直连 HP Laser 136nw打印机设置HP Smart HP Laser 136nw打印机设置 打开打印机WIFI开关&#xff0c;使其他设备可以搜索到 查看打印机设备名称&#xff0c;用于设备搜索 查看打印机WIFI密钥&#xff0c;用于windows与打印机直连 根据…

手写JAVA线程池

前言 手写一个简单的java线程池&#xff1a;重点关注&#xff0c;如何确保一直有运行的线程&#xff1f;如何确保线程消费提交的任务信息&#xff1f;。一直保存有运行的线程底层使用的是死循环。使用消息队列确保信息的提交和消费。消息队列使用先进先出原则。 步骤 线程池…