3.优化算法之二分查找1

二分查找简介

1.特点

最简单最恶心,细节最多,最容易写出死循环的算法

2.学习中的侧重点

1)算法原理

数组有序的情况

2) 模板

不要死记硬背 ->理解之后再记忆

1.朴素的二分模板
2.查找左边界的二分模板
3.查找右边界的二分模板

//后面两个是万能模板,细节很多

1.二分查找 

1)题目描述

2)算法原理

二分查找

根据规律能把数组分为两部分,可以用二分查找(选择中间这个点的时间复杂度是最小的)

 

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

我们在计算mid的时候要考虑数字的溢出

int mid=left+(right-left)/2; 

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

朴素版本的时候 :

mid=left+(right-left+1)/2;==mid=left+(right-left)/2;

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

1)题目描述

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

2)算法原理

仍然是用朴素二分

class Solution {
    public int[] searchRange(int[] nums, int target) {
        //首先进行特殊情况的处理
        if(nums.length==0){
            return new int[]{-1,-1};
        }
        if(nums.length==1){
            return nums[0]==target?new int[]{0,0}:new int[]{-1,-1};
        }
        int l=0,r=nums.length-1;
        while(l<=r){
            int mid=(l+r)/2;
            if(nums[mid]==target){
                l=r=mid;
                //找到左标记
                while(l>=1&&nums[l-1]==target){
                    l--;
                }
                //找到右标记
                while(r<nums.length-1&&nums[r+1]==target){
                    r++;
                }
                return new int[]{l,r};
            }
            if(nums[mid]>target){
                r=mid-1;
            }else{
                l=mid+1;
            }
        }
        return new int[]{-1,-1};
    }
}

但是如果数组全是3的话,我们的时间复杂度又会降成O(N)

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] ret=new int[2];
        ret[0]=ret[1]=-1;
        //1.处理边界条件
        int n=nums.length;
        if(n==0){
            return ret;
        }
        //2.二分左端点
        int left=0,right=n-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 ret;
        }else{
            ret[0]=left;
        }
         //2.二分右端点
        left=0;right=n-1;
        while(left<right){
            int mid=left+(right-left+1)/2;
            if(nums[mid]>target){
                right=mid-1;
            }else{
                left=mid;
            }
        }
        //判断是否有结果
        if(nums[right]!=target){
            return ret;
        }else{
            ret[1]=right;
        }
        return ret;
    }
}

 

3.x的平方根 

69. x 的平方根 - 力扣(LeetCode)

1)题目描述

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

示例 1:

输入:x = 4
输出:2

示例 2:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。

2)算法原理

 

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

4.搜索插入位置 

1)题目描述

35. 搜索插入位置 - 力扣(LeetCode)

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

2)算法原理

class Solution {
    public int searchInsert(int[] nums, int target) {
        //首先进行特殊情况的处理
        if(nums.length==0){
            return 0;
        }
        int left=0,right=nums.length-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;
        }
        return left;
    }
}

left和right相遇了,想写谁写谁 

5.山脉数组的峰顶索引

852. 山脉数组的峰顶索引 - 力扣(LeetCode)

1)题目描述

给定一个长度为 n 的整数 山脉 数组 arr ,其中的值递增到一个 峰值元素 然后递减。

返回峰值元素的下标。

你必须设计并实现时间复杂度为 O(log(n)) 的解决方案。

示例 1:

输入:arr = [0,1,0]
输出:1

示例 2:

输入:arr = [0,2,1,0]
输出:1

示例 3:

输入:arr = [0,10,5,2]
输出:1

2)算法原理

class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int left=0,right=arr.length;
        while(left<right){
            int mid=left+(right-left+1)/2;
            if(arr[mid]>arr[mid-1]){
                //此时说明在左半边
                left=mid;
            }else if(arr[mid]<arr[mid-1]){
                //说明在右侧
                right=mid-1;
            }
        }
        return left;
    }
}

 6.寻找峰值

寻找峰值

1)题目描述

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

你可以假设 nums[-1] = nums[n] = -∞ 。

你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

2)算法原理

 

 

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

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

1)题目描述

153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:

  • 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
  • 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]

注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。

示例 2:

输入:nums = [4,5,6,7,0,1,2]
输出:0
解释:原数组为 [0,1,2,4,5,6,7] ,旋转 3 次得到输入数组。

示例 3:

输入:nums = [11,13,15,17]
输出:11
解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。

提示:

  • n == nums.length
  • 1 <= n <= 5000
  • -5000 <= nums[i] <= 5000
  • nums 中的所有整数 互不相同
  • nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转

2)算法原理

 

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

 8.0~n-1中缺失的数字

1)题目描述

LCR 173. 点名 - 力扣(LeetCode)

某班级 n 位同学的学号为 0 ~ n-1。点名结果记录于升序数组 records。假定仅有一位同学缺席,请返回他的学号。

示例 1:

输入: records = [0,1,2,3,5]
输出: 4

示例 2:

输入: records = [0, 1, 2, 3, 4, 5, 6, 8]
输出: 7

提示:

1 <= records.length <= 10000

2)算法原理 

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

 

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

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

相关文章

同步时钟系统为何能成为机场时间管理的好伙伴?

在机场这个分秒必争的环境中&#xff0c;精准的时间管理至关重要。同步时钟系统的出现&#xff0c;成为了机场时间管理的得力助手&#xff0c;为机场的高效运行和服务质量的提升发挥了关键作用。 一、同步时钟系统简介 同步时钟系统是一种通过网络技术实现时间同步的高精度计时…

python3使用ast.parse详解

使用ast库分析python3脚本, 并对脚本进行一些处理, 比如注释pirnt语句 一.基础知识 官方网址连接 ast — Abstract Syntax Trees ast库可以方便的分析python代码结构, 并做一些处理, 很适合对大量脚本文件做批量处理, 比如把print语句全部注释等. 直观的打印出代码结构 impo…

洞察用户需求,Xinstall数据统计App让你的App运营如虎添翼

在互联网时代&#xff0c;App推广和运营面临着前所未有的挑战。流量红利逐渐衰退&#xff0c;用户获取成本不断攀升&#xff0c;如何确保在多变的互联网环境下&#xff0c;迅速搭建起能时刻满足用户需求的运营体系&#xff0c;成为众多企业急待解决的问题。今天&#xff0c;我们…

简易人工智能入门(2)

上篇文章讨论过了人工智能的几个核心概念&#xff0c;线性模型&#xff0c;损失函数和梯度下降。下面我们继续探讨。 一、几种梯度下降的方式 1、批量梯度下降法&#xff08;Batch Gradient Descent&#xff0c;简称BGD&#xff09;是梯度下降法最初的形式&#xff0c;在更新…

RabbitMQ 入门

目录 一&#xff1a;什么是MQ 二&#xff1a;安装RabbitMQ 三&#xff1a;在Java中如何实现MQ的使用 RabbitMQ的五种消息模型 1.基本消息队列&#xff08;BasicQueue&#xff09; 2.工作消息队列&#xff08;WorkQueue&#xff09; 3. 发布订阅&#xff08;Publish、S…

机器发货到菲律宾的完整流程 广东智慧物流

机器发货到菲律宾的完整流程 广东智慧物流 &#x1f31f;【机器发货到菲律宾完全攻略】&#x1f31f; 机器发货到菲律宾的完整流程 广东智慧物流 为你整理了一份超详细的机器发货到菲律宾的攻略&#xff01;海运14天轻松到达&#xff0c;让你无后顾之忧&#xff01;&#x1f…

昇思25天学习打卡营第3天|MindSpore快速入门-模型训练

基于MNIST_Data.zip手写数据集案例&#xff0c;进行MindSpore模型训练。 MNIST数据集 MNIST数据集由美国国家标准与技术研究所&#xff08;NIST&#xff09;整理发布&#xff0c;最初的目的是实现对手写数字的自动识别。该数据集包含了来自250个不同人的手写数字图片&#xff…

python的一些常用的内建函数

内建函数 python中的内建函数是可以被自动加载的&#xff0c;可以随时调用这些函数&#xff0c;不 需要定义。方便的编程。 eval()函数 将字符串当成有效的表达式来求值&#xff0c;并返回计算结果 用于对动态表达式求值&#xff0c;语法格式如下&#xff1a; eval(source&…

使用Tauri+vite+koa2+mysql开发了一款待办效率应用

&#x1f389;使用Taurivitekoa2mysql开发了一款待办效率应用 &#x1f4dd;项目概述 这是一个基于taurivite的应用&#xff0c;它采用了一些最新的前端技术&#xff0c;包括 Tauri、Vue3、Vite5、koa2 和 mysql。它提供了丰富的效率管理工具。 应用地址&#xff1a;https:/…

排序算法系列一:选择排序、插入排序 与 希尔排序

零、说在前面 本文是一个系列&#xff0c;入口请移步这里 一、理论部分 1.1&#xff1a;选择排序 1.1.1&#xff1a;算法解读&#xff1a; 使用二分法和插入排序两种算法的思想来实现。流程分为“拆分”、“合并”两大部分&#xff0c;前者就是普通的二分思想&#xff0c;将…

首发!麒麟软件打造的跨平台通用Linux端间互联组件Klink正式开源

随着智能终端设备的普及&#xff0c;多个智能终端设备之间的互联互通应用场景日益丰富。多设备互联互通应用场景需要开发者单独实现通讯协议&#xff0c;为解决跨平台问题&#xff0c;麒麟软件打造了跨平台的通用Linux端间互联组件——Klink&#xff0c;并在开源社区openKylin&…

怎么用韩语说帮忙更合体,柯桥零基础韩语培训

1. **详细解释&#xff1a;** - **标准写法与音译&#xff1a;** - **돕다**&#xff08;读作 dop-da&#xff09;&#xff1a;动词“帮助”。 - **도와주다**&#xff08;读作 do-wa-ju-da&#xff09;&#xff1a;动词“帮忙”&#xff0c;字面意思是“给予帮助”。 - **도움…

惠海 H6901B升压恒流3.7V 7.4V 12V 24V 30V 36V 48V 60V 80V 100V LED灯杯方案

H6901B是一款升压型LED恒流驱动芯片&#xff0c;具有良好稳定性的特点。H6901B的主要特点包括宽输入电压范围&#xff08;2.7V-100V&#xff09;、高工作频率&#xff08;1MHz&#xff09;以及多种保护功能&#xff08;如芯片供电欠压保护、过温保护、软启动等&#xff09;。此…

佑驾创新A股夭折再冲港股:三年亏损超5亿,商业化盈利难题何解

《港湾商业观察》廖紫雯 日前&#xff0c;深圳佑驾创新科技股份有限公司&#xff08;以下简称&#xff1a;佑驾创新&#xff09;递表港交所&#xff0c;保荐机构为中信证券、中金公司。佑驾创新曾于2023年8月启动A股上市辅导&#xff0c;但2024年5月公司终止了与辅导机构的上市…

AI 激发算力需求暴增,施耐德电气解码智算中心发展

随着全球碳达峰目标的持续推进&#xff0c;各行各业都在加速绿色转型的步伐&#xff0c;尤其是高耗能产业更是备受关注。人工智能行业以其迅猛的发展速度令人瞩目&#xff0c;它所带来的不仅是算力需求的飙升&#xff0c;更是日益凸显的能耗问题。 目前&#xff0c;人工智能预…

ubuntu中共享文件夹看不到了,解决方法

1、检查共享文件夹配置 2、创建 3、查看共享文件夹 4、另一问题&#xff0c;每次重启虚拟机后&#xff0c;共享文件夹又没了&#xff1f;

【活动】GPT-5:1.5年后的技术飞跃与社会影响展望

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 GPT-5&#xff1a;1.5年后的技术飞跃与社会影响展望引言技术突破&#xff1a;从…

公益培训|半导体与集成电路项目制培训项目

关于我们 硬蛋产业学院&#xff0c;基于硬蛋创新(http://00400.HK)在芯片产业的资源和技术优势&#xff0c;引进全球领先的芯片应用技术&#xff0c;为国内培养芯片应用技术人才&#xff0c;助力芯片应用产业发展。 硬蛋产业学院在国家各主管部门、广东省、深圳市及社会各界的大…

RabbitMQ延时队列(实现定时任务)

消息的TTL(Time To Live)就是消息的存活时间。 RabbitMQ可以对队列和消息分别设置TTL。 对队列设置存活时间&#xff0c;就是队列没有消费者连着的保留时间。 对每一个单独的消息单独的设置存活时间。超过了这个时间&#xff0c;我们认为这个消息就死了&#xff0c;称之为死…

Mac 如何安装 wget

1.安装 Homebrew2.安装 wget3.检测 wget 是否安装成功 1.安装 Homebrew 在安装 wget 之前需要安装一个适用于 mac 的包管理器 Homebrew&#xff0c;打开 mac 终端执行如下命令进行安装&#xff1a; /usr/bin/ruby -e "$(curl -fsSL https://cdn.jsdelivr.net/gh/ineo6/h…