力扣 | 二分查找模板

news2024/12/24 2:10:08

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

力扣:二分查找

文章目录

  • 📚二分查找
  • 📚模板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) overflow
    	int 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 > right
  	return -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;
                else
                    left=mid+1;
            }
            else
            {
                //如果中间位置的元素小于左边界的元素,说明右半部分是有序的。
                //此时,再判断目标元素是否处于右半部分的有序区间内。
                if(target<=nums[right]&&target>nums[mid])
                    left=mid+1;
                else
                    right=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) overflow
    	int 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 == right
  	if(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) overflow
        int 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 == right
    if(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)/2
            int 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 == right
        if(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 == right
        if(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};
        }
        //用两次二分,这里用的是模板II
        vector<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.coloradmin.cn/o/744462.html

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

相关文章

photoshop制作法线和凹凸贴图

做个选区 Ctrlj 法线贴图 生成凹凸贴图

Vue实现多语言(i18n)

第一步 安装i18n插件。 npm install vue-i18n第二步 在src目录下&#xff0c;创建一个【language】文件夹&#xff0c;并创建两个语言包js文件。 中文语言包&#xff1a;【zh.js】 英文语言包&#xff1a;【en.js】 第三步 完善en.js文件和zh.js文件。两个文件的结构要相…

系统架构设计师-项目管理

目录 一、盈亏平衡分析 二、进度管理 1、WBS工作分解结构 2、进度管理流程 &#xff08;1&#xff09;活动定义 &#xff08;2&#xff09;活动排序 &#xff08;3&#xff09;活动资源估算&#xff1a; &#xff08;4&#xff09;活动历时估算&#xff1a; &#xff08;5&…

谷歌浏览器添加首页快捷方式,并设置默认搜索引擎为百度

目录 1、添加首页快捷方式 ​2、谷歌浏览器设置默认搜索引擎 1、添加首页快捷方式 &#xff08;1&#xff09;首先要保证当前的默认搜索引擎为Google才可以添加首页的快捷方式。 &#xff08;2&#xff09;回到首页即可添加和自定义快捷方式的url &#xff08;3&#xff09;默…

Linux——系统文件IO(文件操作符 详解+代码)

文件操作符 1.回顾C语言文件接口总结 2.系统文件IO2.1 open函数介绍2.2代码测试2.3Q :fd为什么是3&#xff1f;012去哪里了&#xff1f;A: 3.如何理解Linux下一切皆文件 1.回顾C语言文件接口 写文件 #include <stdio.h> #include <string.h> int main() { FILE *…

【双指针】24. 两两交换链表中的节点

24. 两两交换链表中的节点 解题思路 dummyNode指向22 指向11 指向3然后移动指针 开始交换 3 4 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* L…

OpenAI GPT-4 Code Interpreter测试

OpenAI GPT-4 Beta版本Code Interpreter功能分析 OpenAI最近在GPT-4中推出了Code Interpreter功能的Beta版本&#xff0c;它是ChatGPT的一个版本&#xff0c;可以编写和执行Python代码&#xff0c;并处理文件上传。以下是对其表现的基本分析。 主要功能 文件信息获取&#xf…

Flutter入门教程(一),2023最新版包含安装,初始化!简单易懂!

Flutter入门教程&#xff08;一&#xff09;&#xff0c;2023最新版包含安装&#xff0c;初始化&#xff01;简单易懂&#xff01; Flutter介绍 首先&#xff0c;在一切的开始之前我们来介绍一下什么是Flutter&#xff0c;Flutter 是一个由 Google 开发的开源移动应用程序开发…

Openlayers实战:加载静态图片作为底图

我们经常会看到一些商场地图或者其他的静态图展示的情况,在Openlayers实战中,我们加载静态图片,使其成为底图,通过缩放,来展示各个部分。 效果图 源代码 /* * @Author: 大剑师兰特(xiaozhuanlan),还是大剑师兰特(CSDN) * @此源代码版权归大剑师兰特所有,可供学习或…

回首2023上半年:成长、思考、感恩

文章目录 每日一句正能量前言一、目标达成情况总结二、工作和学习成果总结三、下半年规划总结四、个人想法 后记附录 每日一句正能量 做一个向日葵族&#xff0c;面对阳光&#xff0c;不自艾自怜&#xff0c;每天活出最灿烂的自己。曾经拥有的&#xff0c;不要忘记。不能得到的…

【JAVA】定时任务之借阅到期自动催还

该篇主要以定时任务为主&#xff0c;通知略为记录 一. 定时任务逻辑代码 定时任务文件 TaskScheduling.java package org.springblade.modules.task;import lombok.extern.slf4j.Slf4j; import org.springblade.modules.archiveAdvantage.service.IArchiveBorrowService; im…

Pytorch基本使用—激活函数

✨1 介绍 ⛄ 1.1 概念 激活函数是神经网络中的一种数学函数&#xff0c;它被应用于神经元的输出&#xff0c;以决定神经元是否应该被激活并传递信号给下一层。常见的激活函数包括Sigmoid函数、ReLU函数、Tanh函数等。 &#x1f384; 1.2 性质 激活函数是神经网络中的一种重…

Markdown基本用法

目录 1 字体倾斜 1.1 加* 1.2 加_ 2 字体加粗 2.1 加** 2.2 加__ 3 字体上带删除线 4 文字变标题 5 超链接 5.1 直接输入地址 5.2 将超链接改成文字 5.2.1 同行写法 5.2.2 不同行写法 6 文字前加 6.1 号 6.2 *号 6.3 -号 7 有序列表 8 …

【微信小程序创作之路】- 小程序常用页面样式

【微信小程序创作之路】- 小程序常用页面样式 第四章 微信小程序用页面样式 文章目录 【微信小程序创作之路】- 小程序常用页面样式前言一、总体样式--全局样式and局部样式1.全局样式2.局部样式 二、Flex布局&#x1f349;&#x1f349;&#x1f349;rpx单位 三、样式导入四、…

HEGERLS四向穿梭车的调度算法如何解决同层多车时车辆路径规划和避让的问题?

纵观全球&#xff0c;消费需求正在发生转变&#xff0c;无论是个体消费还是企业消费&#xff0c;呈现出个性化、定制化、网络化的趋势。因此生产企业面临着产品多样化、订单碎片化、服务定制化的新挑战&#xff0c;仓储密集存储、超大拆零作业量需求愈加明显&#xff0c;且竞争…

苹果平板用不用买原装笔?ipad平替电容笔排行榜

我们应该都知道&#xff0c;第一款ipad早诞生于十年前&#xff0c;如今已是家喻户晓的平板电脑产品。ipad版本系列的更新非常迅速&#xff0c;销售也非常火爆。其中&#xff0c;iPad的配件起到了很大的作用&#xff0c;比如我们今天要介绍的这款电容笔&#xff0c;这款ipad的配…

vue3+ts中常用的两个按钮选择事件写法

1. 效果演示 2.vue3单页面代码演示 <template><div class"btns"><divv-for"(item, index) in nams"click"btnCol(index)":class"current index ? active : btn">{{ item }}</div></div><div clas…

【MySQL】从零开始的JDBC编程

1、JDBC的认识 学了这么久的 MySQL&#xff0c;我们一直采用的都是 MySQL 软件自带的客户端&#xff08;黑框框&#xff09;&#xff0c;来进行跟MySQL服务器进行交互。但是在实际开发中我们很少在黑框框中手动输入SQL&#xff0c;大多数都是通过代码自动执行SQL的。既然大多数…

单片机第一季:零基础4——LED点阵

1&#xff0c;第八章-LED点阵 如何驱动LED点阵&#xff1a; (1)单片机端口直接驱动。要驱动8*8的点阵需要2个IO端口&#xff08;16个IO口&#xff09;、要驱动16*16的点阵需要4个IO端口&#xff08;32个IO口&#xff09;。 (2)使用串转并移位锁存器驱动。要驱动16*16点阵只需要…

7.3Java EE——Bean的实例化

一、构造方法实例化 下面通过一个案例演示Spring容器如何通过构造方法实例化Bean。 &#xff08;1&#xff09;、在IDEA中创建一个名为chapter07的Maven项目&#xff0c;然后在项目的pom.xml文件中配置需使用到的Spring四个基础包和Spring的依赖包。 <dependencies>&…