二分算法详解

news2024/11/30 1:26:11

 

在这里插入图片描述

1. 二分查找

704. 二分查找

这是一道单纯的朴素二分模版题,当 left == right 时的这种情况也是需要考虑的,因为不排除数组中只有一个数的情况,或者是二分到数组中只剩一个数的情况,所以循环条件要写 left <= right

class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1, mid = 0;
        while (left <= right) {
            mid = (left + right) / 2;
            if (nums[mid] > target) {
                right = mid - 1;
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }
}

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

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

求区间左端点 :

可以把区间分为两部分,一部分是 x < t 的情况,另一部分就是 x >= t 的情况,由于 x < t 中不包含答案,所以可以把 left = mid + 1,跳出这部分,同理,由于答案在右半部分,所以 right = mid ,就不能跳出这个区间了,又因为这个区间都是 x >= t 的,所以最后也一定会找到左端点

关于循环条件:

当最后需要执行更新 right 的操作时,如果说此时 left 和 right 指向了同一个位置,那么算出来的 mid 还是这个位置,更新的 right 还是此时的位置,会一直重复这个操作,导致死循环,同时无论是有结果的情况还是没有结果的情况,当 left 和 right 指向了同一个位置这个时候都需要退出循环,所以说循环条件就不能包含等于了

求中点的操作:

当数组是偶数的时候,中点的位置会有两个,如果加一就是右边的中点,不加就是左边的中点,因为上面 right 是移动到 mid 的位置的,如果这里按照右边的中点就会死循环,按照左边的中点就可以正常的退出循环

求区间右端点:

和求左端点相反,这里是把小于等于目标值分为一个区间,大于目标值分为一个区间,所以说 left 就只能移动到 mid 的位置了,如果移动到 mid + 1 就会错过答案,同理 right 是需要移动到 mid - 1 的位置去寻找答案的

关于循环条件:

这里的条件和区间左端点是一样的,都是不能写等号

求中点的操作:

由于这一次需要将 left 移动到 mid 的位置,所以说就不能求左边的中点了,需要求右边的中点才能退出循环

之后再处理一下特殊情况就可以了:当数组为空时或者循环结束后没有找到目标值的情况

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] ans = new int[2];
        if (nums.length == 0) {
            ans[0] = -1;
            ans[1] = -1;
            return ans;
        }
        int left = 0, right = nums.length - 1, mid = 0;
        //左端点
        while (left < right) {
            mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        if (nums[right] == target) {
            ans[0] = right;
        } else {
            ans[0] = -1;
        }
        //left = 0;
        right = nums.length - 1;
        while (left < right) {
            mid = left + (right - left + 1) / 2;
            if (nums[mid] > target) {
                right = mid - 1;
            } else {
                left = mid;
            }
        }
        if (nums[right] == target) {
            ans[1] = right;
        } else {
            ans[1] = -1;
        }
        return ans;
    }
}

3. x 的平方根

69. x 的平方根

题目要求小数部分要舍去,要求的是算术平方根,平方之后是小于等于 x 的,也就是要求区间的左端点的问题

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

4. 搜索插入位置

35. 搜索插入位置

无论是要插入的位置还是找到目标值,所在的区间都是 >= 目标值的区间,也就是查找区间左端点的情况,最后如果找到了目标值直接返回下标,找不到就返回下标 + 1,也就是要插入的位置

class Solution {
    public int searchInsert(int[] nums, int target) {
        if(nums[0] > target) return 0;
        int left = 0, right = nums.length - 1, mid = 0;
        while (left < right) {
            mid = left + (right - left + 1) / 2;
            if (nums[mid] > target) {
                right = mid - 1;
            } else {
                left = mid;
            }
        }
        if (nums[left] == target)
            return left;
        else
            return left + 1;
    }
}

5. 山脉数组的峰顶索引

852. 山脉数组的峰顶索引

这道题并不像上面的题一样,要查找的区间是有序的,这道题虽然不是有序的但是具有二段性,所以也可以使用二分来解决

关于峰值:第一个前一个元素大于后一个元素的位置

根据上面的分法就是求区间的右端点,如果把峰值分到右区间就是求区间左端点,这里以右端点为例:

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

6. 162. 寻找峰值

162. 寻找峰值

这道题和上一道题不同的是会有多个峰值,需要找到其中的一个峰值,虽然有很多峰值,但是经过分析,还是可以发现存在二段性:

首先是可能会有三种情况的

无论是哪种情况,都可以找到以下的状态

也就可以有以下的结论:

nums[mid] > nums[mid + 1] : right = mid

nums[mid] < nums[mid + 1] : left = mid + 1

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

7. 寻找旋转排序数组中的最小值

153. 寻找旋转排序数组中的最小值

每一次旋转就是把最后一位的元素移动到第一位,题目就是求旋转后的数组中的最小值,这道题也可以分析出二段性,由于题目中已经明确指出了是互不相同的数组,所以可以得出以下结论:

将数组可以分为两段,左边的半段都是比右边的大的,所以答案也就在右边,就需要让 left = mid + 1,同理,如果 mid 落到右边,那么就是 right = mid ,从而不错过答案

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

上面是以 nums[n - 1] 作为对照,也可以把第一个元素作为对照,不过此时就需要考虑翻转之后的数组如果一直都是递增的特殊情况

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

8. LCR 173. 点名

LCR 173. 点名

这道题是有多种解法的:

第一种:哈希表,把 0 ~ n - 1 的数丢到哈希表中,然后遍历求解

第二种:直接遍历

第三种:位运算

第四种:高斯求和,相减

上面的解法时间复杂度都是 O (n) 的,用二分的话就需要去找它的二段性

可以通过下标入手,左边区间下标是对应的,右边的是数组元素比下标大的

此外,还有一种特殊情况,就是数组中的元素和下标都是对应的,此时缺少的数字就是 n

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

在这里插入图片描述

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

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

相关文章

批量复制文件技巧:高效管理,一键复制至指定位置

当需要处理大量文件时&#xff0c;批量复制功能能显著提升工作效率。通过文件管理器或专业的文件处理软件&#xff0c;用户可以一次性选择多个文件或文件夹进行复制操作&#xff0c;无需逐个手动操作&#xff0c;大大节省了时间。还可以实现更复杂的批量处理任务。 1.打开“文件…

Qt开发技巧(十四)文字的分散对齐,设置动态库路径,进度条控件的文本,文件对话框的卡顿,滑块控件的进度颜色,停靠窗体的排列,拖拽事件的坑

继续讲一些Qt开发中的技巧操作&#xff1a; 1.文字的分散对齐 有时候需要对文本进行分散对齐显示&#xff0c;相当于无论文字多少&#xff0c;尽可能占满整个空间平摊占位宽度&#xff0c;但是在对支持对齐方式的控件比如QLabel调用 setAlignment(Qt::AlignJustify | Qt::Align…

移动硬盘无法读取?详解原因与数据恢复方案

一、移动硬盘无法读取现象描述 在日常生活中&#xff0c;移动硬盘作为我们存储和传输数据的重要工具&#xff0c;扮演着不可或缺的角色。然而&#xff0c;有时我们会遇到移动硬盘无法读取的情况&#xff0c;这给我们的数据使用带来了极大的困扰。当我们将移动硬盘连接到电脑或…

LLM大模型学习精要系列(一):掌握基础,开启大模型之旅

1.前言 1.1 基础模型研究 2023 年&#xff0c;随着 LLM 技术的发展&#xff0c;中国模型研究机构的开源模型迎来了爆发式的增长&#xff1a; 2023 年 3 月&#xff0c;智谱 AI 首先在魔搭社区发布了 ChatGLM-6B 系列&#xff0c;ChatGLM-6B 是一个开源的、支持中英双语问答的…

【EXCEL数据处理】000001 案列 条件格式之大于,小于,介于,等于。使用的软件是微软的Excel操作的。处理数据的目的是让数据更直观的显示出来,方便查看。

【EXCEL数据处理】000001 案列 条件格式之大于,小于,介于,等于。使用的软件是微软的Excel操作的。处理数据的目的是让数据更直观的显示出来&#xff0c;方便查看。 &#x1f4da;一、直接上案例 &#x1f4d6;1.EXCEL条件格式之大于,案列。标记值大于1500000的值为粉红色。 &a…

【游戏模组】重返德军总部2009高清重置MOD,建模和材质全部重置,并且支持光追效果,游戏画质大提升

各位好&#xff0c;今天小编给大家带来一款新的高清重置MOD&#xff0c;本次高清重置的游戏叫《重返德军总部2009》2009年发布&#xff0c;我相信很多玩家已经玩过了&#xff0c;如果你还没有玩过我也可以和你简单介绍一下剧情&#xff0c;这款游戏故事背景接续在《重返德军总部…

memset二维数组

1135 用 sizeof d sizeof d[] sizeof N*4 都是错误的。 void dijkstra(int s,int d[]) {memset(d,0x3f,N*4);memset(st,0,sizeof st);d[s]0;priority_queue<PII,vector<PII>,greater<PII>>q;q.push({0,s});while(q.size()){auto tq.top();q.pop();in…

AI大模型开发智能机票助手源码

智能机票助手&#xff1a;使用 Spring AI Alibaba 构建 在本篇文章中&#xff0c;我们将探讨如何使用 Spring AI Alibaba 框架来构建一个智能机票助手。这个助手将能够帮助用户完成机票预订、解答问题、改签和取消等服务。 项目概述 智能机票助手的目标是利用 AI 技术来提升…

【数学分析笔记】第4章第4节 复合函数求导法则及其应用(3)

4. 微分 4.4 复合函数求导法则及其应用 【例4.4.9】向斜向上方向抛一个物体&#xff0c;当 t 0 t0 t0时&#xff0c;水平速度与垂直向上的速度分别为 v 1 v_1 v1​和 v 2 v_2 v2​&#xff0c;问在什么时刻速度的方向是水平的&#xff1f; 【解】该物体画出来的轨迹是抛物线…

【Canvas与艺术】金属底座洞眼红心按钮

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>金属底座洞眼红心按钮</title><style type"text/css&q…

校企合作必备无人机兴趣班技术详解

校企合作中的无人机兴趣班技术详解&#xff0c;可以从以下几个方面进行阐述&#xff1a; 一、合作背景与目标 随着无人机技术的飞速发展&#xff0c;无人机在航拍、农业、环境监测、应急救援等多个领域展现出巨大的应用潜力。市场对无人机专业人才的需求日益增长&#xff0c;…

STM32中断——外部中断

目录 一、概述 二、外部中断&#xff08;Extern Interrupt简称EXTI&#xff09; 三、实例-对射式红外传感器 1、配置中断&#xff1a; 2 、完整代码 一、概述 中断&#xff1a;在主程序运行过程中&#xff0c;出现了特定的中断触发条件(中断源)&#xff0c;使得CPU暂停当…

【WebGis开发 - Cesium】三维可视化项目教程---视点管理

目录 引言一、基础功能探索1. 镜头视角获取2. 镜头视角移动 二、进一步封装代码1. 封装hooks函数2. 看下效果3. 如何使用该hooks函数 三、总结 引言 本教程主要是围绕Cesium这一开源三维框架开展的可视化项目教程。总结一下相关从业经验&#xff0c;如果有什么疑问或更好的见解…

SQL自用小结

推荐一下这个知识点总结 《数据库系统概论》第五版 学习笔记总目录 1. SQL概述 SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;是一种用于定义、查询、更新和控制关系数据库的标准化语言。 它包含了数据定义语言&#xff08;DDL&#xff0…

(19)MATLAB使用Nakagami 分布对象生成Nakagami-m分布

文章目录 前言一、生成Nakagami分布随机变量的MATLAB代码1.仿真代码2.运行结果 二、传输信号经过衰落信道 前言 MATLAB在R2013a版本中开始引入Nakagami分布对象&#xff0c;可以用来生成Nakagami随机变量。下面给出一个使用实例&#xff0c;用于生成服从Nakagami 分布的随机变…

实战五:模拟10086查询功能

问题描述&#xff1a; 输入1&#xff0c;显示当前余额;输入2&#xff0c;显示当前的剩余流量&#xff0c;单位为G;输入3&#xff0c;显示当前的剩余通话&#xff0c;单位为分钟;输入0,退出自助查询系统。 编程&#xff1a; 1.方法一&#xff1a; # (1)初始化变量 answer y…

Java.数据结构.HashMap

目录 1基本概念 2数据结构 3常用操作 3.1 put(K key, V value)&#xff1a;插入键值对。 3.2 get(Object key)&#xff1a;根据键获取值。 3.3 remove(Object key)&#xff1a;移除键值对。 3.4 containsKey(Object key)&#xff1a;判断Map中是否包含指定的键。 3.5 c…

【Orange Pi 5 嵌入式应用编程】-用户空间SPI通信

用户空间SPI通信 文章目录 用户空间SPI通信1、理解SPI通信协议1.1 什么是SPI通信协议1.2 SPI如何工作?1.3 SPI数据传输步骤1.4 SPI的优缺点2、嵌入式Linux系统中的SPI通信3、Orange Pi 5 配置与编程3.1 Orange Pi 5开发板配置SPI3.2 SPI编程实现3.2.1 SPI用户空间函数定义3.2.…

Kafka 快速入门

目录 介绍 KafKa 相关术语 ​编辑 Kafka的工作流程 生产者向kafka发送数据的流程 Kafka选择分区的模式 Kafka选择分区的模式 数据消费 kafka的文件存储机制 topic、partition和segment 存储和查找message的过程 数据写入过程 数据查找过程 注意事项 kafka管理UI …

基于Springboot+Vue的高校学术交流平台 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统中…