二分法题集1

1 二分查找

分析:

这是一道很简单的二分法题,定义两个指针和中间值middle,判断middle对应数组值与目标值的大小关系,从而对left和right进行修改。由于太过基础,代码简单基础就不多赘述。

目录

1 二分查找

分析:

代码展示:

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

分析:

代码展示:

3 搜索插入位置

分析:

代码展示:

4 x 的平方根 

分析:

代码展示:


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

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

分析:

这道题要求时间复杂度为logn,如果遍历数组时间复杂度最坏就是n,而时间复杂度为logn那就需要用二分法。

注意 二分法不一定要求数组有序,只要该数组存在二段性就可以用二分法。何为二段性,就是通过一个性质可以把数组划分为两段。比如在这道题中我们如果找第一个目标值就可以划分为小于target的为左端,大于等于targert的为右端。

我们定义两个指针left 和 right 分别指向下标0和下标nums.length - 1 。拿案例一分析,left到第一个最后一个7是小于8的区域,第一个8到right是大于等于8的区域。我们用middle来判断当前值与目标值的大小情况。如果小于目标值那么就让left = middle + 1;如果大于那么就让right = middle。

这时我们会发现如果目标值存在于数组,那么left最后一定会指向第一个目标值,因为小于目标值那么就会让left = middle +1,所以必然有middle + 1等于目标值,而且一定是第一个目标值。

代码展示:
class Solution {
    public int[] searchRange(int[] nums, int target) {
        if(nums.length == 0) {
            return new int[]{-1,-1};
        }
      
        int left = 0;
        int right = nums.length  - 1;
        int[] arr = new int[2];

        //找第一个数
        while(left < right) {
            int middle = left + (right - left) / 2;
            if(nums[middle] < target) {
                left = middle + 1;
            }else {
                right = middle;
            }
        }
        if(nums[left] == target)
        arr[0] = left;
        else arr[0] = -1;
        //找最后一个数
        left = 0;
        right = nums.length - 1;
        while(left < right) {
            int middle = left + (right - left + 1) / 2;
            if(nums[middle] <= target) {
                left = middle;
            }else{
                right = middle - 1;
            }
        }
        if(nums[left] == target) arr[1] = right;
        else arr[1] = -1;
        return arr;

    }
}

这里有很多细节:

1 while循环的条件必须是left < right:
第一点是因为,如果两个指针相遇那么一定会出结果只需要判断最后是不是目标值即可。第二点是因为(核心),如果条件是left <= right,那么代码就会死循环,当两个指针同时指向目标值时,由于nums[middle] = target,因此right = middle。此时就会不断循环。

2 我们可以看到寻找第一个数和最后一个数的middle求法是不一样的。middle = left + (right - left) / 2 这个求出的中间数是偏左的(比如left指向0下标,right指向1下标,那么这个公式求出的middle最后会指向0下标,相反middle = left + (right - left + 1)/2指向的就是指向1下标),由于上述我们提到如果数组中存在目标值,那么left最终一定会指向第一个目标值,所以我们要求middle是要偏向left一方,还有一个原因就是避免死循环,如果middle偏向right一方,那么right = middle;而求出的middle又指向right。

求最后一个数和求第一个数原理相同,只需要将letf到小于等于目标值划分为左区域,大于目标值划分为有区域,一旦nums[middle[大于目标值就让right = middle - 1.那么如果数组中存在该目标值,right一定会指向目标值的最后一位。

3 搜索插入位置

分析:

做完了上一道题,这道题就显得很简单了。我们看示例二,如果目标值是2,那么我们输出的结果是3的下标。我们可以想到,将小于目标值到left划分为一个区域,大于目标值到right划分为一个区域,那么当nums[middle]小于目标值时,left = middle + 1就能找到最后的结果。我们可以总结为第一个大于目标值的数等同于找第一个目标值,最后一个小于目标值的数等同于找最后一个目标值,方法都是一样的。

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

    }
}

前两行代码是出去特殊情况,后面方法则等同于上一道题。

4 x 的平方根 

分析:

这道题我们仍然可以用二分法,比如定义一个x长的数组,并求出每一个数组下标的平方值,如果平方值是最后一个小于或者等于目标值的那么就返回该下标。二位破门上面总结了,如果是求最后一个小于目标值的,那么right = middle - 1一定会指向最后一个小于或者等于该目标值的下标。

代码展示:
class Solution {
    public int mySqrt(int x) {
       if(x < 1) return 0;
        long left = 1;
        long right = x / 2;
        while(left < right) {
            long middle = left + (right - left + 1) / 2;
            if(middle * middle > x) right = middle - 1;
            else left = middle ;
        }
        return (int)left;

    }
}

这里我们要考虑,范围,由于middle * middle结果太大所以需要用到Long类型,并且最后返回值要强转。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PyQt PySide6零基础入门与项目实战视频教程

目录 课程亮点课程大纲第一章&#xff1a;基础篇 PySide6开发环境安装第二章 控件与布局篇 PySide6常用控件与界面布局使用介绍第三章 信号槽与事件机制第四章 QMainWindow应用篇第五章 样式表qss与自定义控件第六章 图表与曲线第七章 数据库编程第八章 项目实战&#xff1a;高…

FJSP:小龙虾优化算法(Crayfsh optimization algorithm,COA)求解柔性作业车间调度问题(FJSP),提供MATLAB代码

一、柔性作业车间调度问题 柔性作业车间调度问题&#xff08;Flexible Job Shop Scheduling Problem&#xff0c;FJSP&#xff09;&#xff0c;是一种经典的组合优化问题。在FJSP问题中&#xff0c;有多个作业需要在多个机器上进行加工&#xff0c;每个作业由一系列工序组成&a…

二叉树的介绍

学习堆排序时先了解下二叉树&#xff0c;因为堆排序中使用了二叉树。 一、二叉树介绍 二叉树&#xff08;binary tree&#xff09;树的每个节点最多有2个孩子节点。注意&#xff0c;这里是最多有2个&#xff0c;也可能只有1个&#xff0c;或者没有孩子节点。 二叉树结构如图…

极客时间: 用 Word2Vec, LangChain, Gemma 模拟全本地检索增强生成(RAG)

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

「 典型安全漏洞系列 」11.身份验证漏洞详解

身份验证是验证用户或客户端身份的过程。网站可能会暴露给任何连接到互联网的人。这使得健壮的身份验证机制成为有效的网络安全不可或缺的一部分。 1. 什么是身份验证 身份验证即认证&#xff0c;是验证给定用户或客户端身份的过程。身份验证漏洞使攻击者能够访问敏感数据和功…

RobotFramework测试框架(12)--第三方库

Library 关于射频指南 |机器人框架 (robotframework.org) 使用RF需要使用Library&#xff0c;常用的第三方库如下&#xff1a; 在web浏览器中进行web应用程序测试可以使用的库是 Selenium Library 在内部使用流行的 Selenium 工具的 Web 测试库Browser Library 由 Playwri…

ThingsBoard通过MQTT发送遥测数据

MQTT基础 客户端 MQTT连接 遥测上传API 案例 MQTT基础 MQTT是一种轻量级的发布-订阅消息传递协议&#xff0c;它可能最适合各种物联网设备。 你可以在此处找到有关MQTT的更多信息&#xff0c;ThingsBoard服务器支持QoS级别0&#xff08;最多一次&#xff09;和QoS级别1&…

【前沿模型解析】潜在扩散模 1 | LDM第一阶段-感知图像压缩总览

文章目录 0 开始~1 感知压缩的目的2 自回归编码器-解码器生成模型一览2.1 AE 自编码器2.2 VAE 变分自编码器2.3 VQ-VAE2.4 VQ-GAN 3 代码部分讲解总览 0 开始~ 从今天起呢&#xff0c;我们会剖析LDM&#xff08;潜在扩散模型&#xff09; 从去年开始&#xff0c;大量的生成模…

蓝桥杯嵌入式(G431)备赛笔记——按键模块设计

目录 cubeMX配置: 代码模板: 最终模板 注意: cubeMX配置: 原理图 引脚配置为上拉模式 定时器 使用定时器3(通用定时器,使用外部晶振,内部时钟),分频系数为80(从0开始则为80-1),则每1s 1m次,定时评率为为10000,对应1s 1m/10000次,频率为10ms每次 一定记得开启…

【SCI绘图】【小提琴系列1 python】绘制按分类变量分组的垂直小提琴图

SCI&#xff0c;CCF&#xff0c;EI及核心期刊绘图宝典&#xff0c;爆款持续更新&#xff0c;助力科研&#xff01; 本期分享&#xff1a; 【SCI绘图】【小提琴系列1 python】绘制按分类变量分组的垂直小提琴图&#xff0c;文末附完整代码 小提琴图是一种常用的数据可视化工具…

java小作业(4)--编写一个类(第一遍)

1.题目&#xff1a; 2.官方代码&#xff1a; // 宠物基类 class Pet {protected double foodPricePerJin; // 食物单价&#xff08;元/斤&#xff09; protected double foodQuantityPerDay; // 每天所需食物量&#xff08;斤&#xff09; // 计算每天的食物花费 public…

Prefetch

Prefetch &#xff08;<link rel"prefetch">&#xff09; 是一种浏览器优化&#xff0c;它允许我们在需要后续路由或页面之前获取可能需要的资源。可以通过几种方式实现预取。它可以在 HTML 中以声明方式完成&#xff08;例如在下面的示例中&#xff09;&#…

什么是广播系统语言传输指数 STIPA

基础知识 通过广播系统播放一个确定的信号&#xff08;STIPA 测试信号&#xff09;&#xff0c;再在待测点测量其到达后的质量即可。IEC 60268-16 标准中定义通过单一值表示清晰度结果&#xff0c;0 表示完全无法理解&#xff0c;1 表示完美理解。测量单位是 STI&#xff08;语…

Linux文件种类、扩展名与目录配置详解

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Linux &#xff1a;从菜鸟到飞鸟的逆袭》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、Linux的起源与发展 二、Linux文件种类 1、纯…

Spring的事务详解

Spring的事务详解 一&#xff0c;什么是Spring事务 Spring 事务是 Spring 框架提供的一种对事务进行管理的机制。在使用 Spring 事务时&#xff0c;可以通过注解或编程方式将需要进行事务管理的方法和代码块标记为事务性操作&#xff0c;当这些操作被执行时&#xff0c;Spring…

数据库基础:概念、分类、作用和特点

文章目录 概要DB-Engines 排名数据库的分类数据库的作用数据库的特点数据库的应用小结 概要 数据库是按照数据结构来组织、存储和管理数据的仓库。它是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。数据库可以被视为电子化的文件柜&#xff0c;用…

详细分析Python爬虫中的xpath(附Demo)

目录 前言1. 基本知识2. 常用API3. 简易Demo 前言 关于爬虫的基本知识推荐阅读&#xff1a;Python爬虫从入门到应用&#xff08;超全讲解&#xff09; 该知识点需要提前安装相关依赖&#xff1a;pip install lxml 1. 基本知识 XPath&#xff08;XML Path Language&#xf…

torchvision中的数据集使用

torchvision中的数据集使用 使用和下载CIFAR10数据集 输出测试集中的第一个元素&#xff08;输出img信息和target&#xff09; 查看分类classes 打断点–>右键Debug–>找到classes 代码 import torchvisiontrain_set torchvision.datasets.CIFAR10(root"./data…

数据结构|排序总结(1)|直接插入排序

排序分类 插入排序&#xff1a;直接插入排序&#xff0c;希尔排序 选择排序&#xff1a;选择排序&#xff0c;堆排序 交换排序&#xff1a;冒泡排序&#xff0c;快速排序 归并排序 插入排序 直接插入排序 相当于摸牌&#xff0c;例如我们现在手上有{2&#xff0c;4&#xff0…

基于单片机光伏太阳能跟踪系统设计

**单片机设计介绍&#xff0c;基于单片机光伏太阳能跟踪系统设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机光伏太阳能跟踪系统的设计&#xff0c;旨在通过单片机技术实现对光伏太阳能设备的自动跟踪&#xff0c;以提高太阳…