TOP100 二分法

写在前面:二分法用在有序序列上

1.35. 搜索插入位置

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

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

示例 1:

输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:

输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:

输入: nums = [1,3,5,6], target = 7
输出: 4

提示:

  • 1 <= nums.length <= 10^4
  • -10^4 <= nums[i] <= 10^4
  • nums 为 无重复元素 的 升序 排列数组
  • -10^4 <= target <= 10^4

思路:

查找元素,又必须是lgn的复杂度,肯定是二分了。

其实二分法有两种写法,最主要的就是要分清楚不变量,或者说主要就在于如何去判断边界。

下面借卡哥的讲法介绍给大家:
1)判断边界为左闭右闭,此时while(left<=right),当nums[middle]>key时,需要将right=middle-1;因为middle在本循环中是要计算进的,当前这个middle肯定不是key值。

2)如果说定义 target 是在一个在左闭右开的区间里,也就是[left, right) ,那么二分法的边界处理方式则截然不同。
有如下两点:

  • while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的
  • if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]

【摘自:代码随想录 (programmercarl.com)】

代码:

class Solution:def searchInsert(self, nums: List[int], target: int) -> int:left,right = 0,len(nums)-1while left<=right:middle=left+(right - left)//2if nums[middle] > target:right=middle-1elif nums[middle] < target:left=middle+1else:return middlereturn right+1

思考:

通过AC发现了,当不存在该元素时,该元素所在位置为right+1

2.74. 搜索二维矩阵

给你一个满足下述两条属性的 m x n 整数矩阵:

  • 每行中的整数从左到右按非严格递增顺序排列。
  • 每行的第一个整数大于前一行的最后一个整数。

给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。

示例 1:

输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出:true

示例 2:

输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
输出:false

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 100
  • -10^4 <= matrix[i][j], target <= 10^4

思路:

由于二维矩阵固定列的「从上到下」或者固定行的「从左到右」都是升序的。

因此我们可以使用两次二分来定位到目标位置:

第一次二分:从第 0 列中的「所有行」开始找,找到合适的行 row

第二次二分:从 row 中「所有列」开始找,找到合适的列 col

代码:java

class Solution {public boolean searchMatrix(int[][] matrix, int target) {int m = matrix.length, n = matrix[0].length;// 第一次二分:定位到所在行(从上往下,找到最后一个满足 matrix[x]][0] <= t 的行号)int l=0,r=m-1;while(l<r){int mid=l+r+1 >> 1;if(matrix[mid][0]<=target){l=mid;}else{r=mid-1;}}int row = r;if(matrix[row][0]==target)return true;if(matrix[row][0]>target)return false;//第二次二分l=0;r=n-1;while(l<r){int mid=l + r + 1 >> 1;if(matrix[row][mid]<=target){l=mid;}else{r=mid-1;}}int col =r;return matrix[row][col] == target;}
}

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

给你一个按照非递减顺序排列的整数数组 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]

提示:

  • 0 <= nums.length <= 10^5
  • -10^9 <= nums[i] <= 10^9
  • nums 是一个非递减数组
  • -10^9 <= target <= 10^9

思路:

1.第一种想法:

边界不要想太多,就两段二分查找就好,不要找到一个mid后再循环左右移动下标,这样时间复杂度在一些情况下会退化为O(N)

2.第二种想法:

考虑 target开始和结束位置,其实我们要找的就是数组中「第一个等于 target的位置」(记为 leftIdx)和「第一个大于 target的位置减一」(记为 rightIdx)。

代码:

第一种:python

class Solution:def searchRange(self, nums: List[int], target: int) -> List[int]:def search(self,nums:List[int],target:int,left:int,right:int,lower:bool):res=-1while left<=right:mid=(left+right)//2if nums[mid]<target:left=mid+1elif nums[mid]>target:right=mid-1elif nums[mid]==target and lower:res = midright=mid-1elif nums[mid]==target:res=midleft=mid+1return resn=len(nums)left,right=0,n-1res=[]res.append(search(self,nums,target,left,right,True))if res[0]==-1:return [-1,-1]res.append(search(self,nums,target,left,right,False))return res

第二种:

class Solution {public int[] searchRange(int[] nums, int target) {int leftIdx = binarySearch(nums, target, true);int rightIdx = binarySearch(nums, target, false) - 1;if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {return new int[]{leftIdx, rightIdx};} return new int[]{-1, -1};}public int binarySearch(int[] nums, int target, boolean lower) {int left = 0, right = nums.length - 1, ans = nums.length;while (left <= right) {int mid = (left + right) / 2;if (nums[mid] > target || (lower && nums[mid] >= target)) {right = mid - 1;ans = mid;} else {left = mid + 1;}}return ans;}
}

4.33. 搜索旋转排序数组

整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

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

示例 1:

输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4

示例 2:

输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1

示例 3:

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

提示:

  • 1 <= nums.length <= 5000
  • -10^4 <= nums[i] <= 10^4
  • nums 中的每个值都 独一无二
  • 题目数据保证 nums 在预先未知的某个下标上进行了旋转
  • -10^4 <= target <= 10^4

思路:

首先寻找旋转点的序号,设为W,然后直接将其旋转复原(使用列表的切片方法),旋转后就是正常的非递减序列,然后进行二分查找,找到后按照以下图解,可知,需要对现有序号做一个映射!

具体映射转换关系,见代码!

代码:

class Solution:def search(self, nums: List[int], target: int) -> int:warn=0n=len(nums)i=1while i <= n-1:#寻找旋转点的序号,[4,5,6,1,2,3]即warn=3if nums[i]<nums[i-1]:start=nums[i:]warn=inums=start+nums[:i]# print(nums)breaki+=1left,right=0,len(nums)-1res=-1while left <= right:#正常有序情况下的二分,查出来的顺序,应该要进行映射mid = left+(right-left)//2if nums[mid]>target:right=mid-1elif nums[mid]<target:left=mid+1else:res=mid# print(res)breakif res==-1:# print(".."+str(res))return resif res < n-warn:#如果位置(下标)在旋转的前半段上,也就是小于n-warnreturn res+warnelse:#否则就在后半段,那么就应该将res-warn,也就是前移warn位(错了),应该是移动(n-warn)位return res-n+warn

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

已知一个长度为 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 次旋转

思路:

代码:

6.4. 寻找两个正序数组的中位数

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

思路:

代码:

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

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

相关文章

Ubuntu20从0开始选择合适版本手动安装cuda,torch-geometric,jax

一个全新的ubuntu20台式机&#xff0c;在Additional Drivers安装nvidia-470-server&#xff08;一开始安装450&#xff0c;cunda版本只能到11.0&#xff0c;torch有些库用不了&#xff0c;可以直接切换点击Apply Changes重启就行&#xff09; nvidia-smi查看CUDA Version可到…

全球最新国内外18个热门风景视频素材网站推荐

寻找最新的高清风景视频素材&#xff1f;这里有国内外共18个热门网站&#xff0c;精心整理供您选择。 国内资源&#xff1a; 蛙学网&#xff1a;免费提供多种无版权视频素材&#xff0c;资源丰富。新GG网&#xff1a;需QQ登录&#xff0c;提供丰富的视频模板&#xff0c;通过…

vue快速入门(十七)v-model数据双向绑定修饰符

注释很详细&#xff0c;直接上代码 上一篇 新增内容 v-model.trim 自动去除首尾空格v-model.number 自动转换成数字类型 源码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" con…

基于ADB的Scrcpy实现电脑控制手机

Scrcpy是一个开源的&#xff0c;基于ADB&#xff08;Android 调试桥&#xff09;的手机到电脑上的投屏操控的实现&#xff0c;本文将介绍如何搭建开发环境&#xff0c;使得在Windows系统中去控制投屏的安卓手机。 1. 安装投屏软件 下载Scrcpy软件到电脑上&#xff0c;该软件中…

YoloV9实战:从Labelme到训练、验证、测试、模块解析

模型实战 训练COCO数据集 本次使用2017版本的COCO数据集作为例子&#xff0c;演示如何使用YoloV8训练和预测。 下载数据集 Images: 2017 Train images [118K/18GB] &#xff1a;http://images.cocodataset.org/zips/train2017.zip2017 Val images [5K/1GB]&#xff1a;htt…

【电控笔记2.2】电流回路+延迟效应

延迟效应的来源以及影响 数字控制系统的delay: 5.4节有介绍T0=0.5TS 低通滤波器的时间常数? 滤波器的传递函数与性能参数

【多线程】阻塞队列 | put()方法 | take()方法 | 生产者-消费者模式 |实现阻塞队列

文章目录 阻塞队列1.生产者-消费者模式生产者消费者模型的意义&#xff1a;1.解耦合2.削峰填谷&#xff1a; 2.阻塞队列的使用BlockingQueue 3.实现阻塞队列唤醒&#xff1a;使用阻塞队列实现生产者消费者模型 阻塞队列 阻塞队列是一种特殊的队列&#xff1a; 1.是线程安全的。…

Vue 阶段练习:记事本

将 Vue快速入门 和 Vue 指令的学习成果应用到实际场景中&#xff08;如该练习 记事本&#xff09;&#xff0c;我们能够解决实际问题并提升对 Vue 的技能掌握。 目录 功能展示 需求分析 我的代码 案例代码 知识点总结 功能展示 需求分析 列表渲染删除功能添加功能底部统计…

网络—DAY4

思维导图 多进程并发服务器 #include<myhead.h> #define SER_IP "192.168.122.56" #define SER_PORT 8888 void handler(int signo) {if(signoSIGCHLD){while(waitpid(-1,NULL,WNOHANG)>0);} } int main(int argc, char *argv[]) {//将SIGCHLD信号与处理…

项目中,如何写 readme.md 文件 | 写项目总结

tips&#xff1a;注意写 1. readme文件&#xff1a;①项目文档&#xff08;项目需求和设计文档、项目系统架构和技术文档、接口文档&#xff09;、②项目结构、③启动项目。具体结构见下文。 2. 项目总结&#xff1a;技术栈、描述、主要工作&#xff01;&#xff01;需求及功…

递归、搜索与回溯算法——递归

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享递归,搜索与回溯算法关于递归的专题 如果有不足的或者错误的请您指出! 目录 1.什么时候使用递归2.汉诺塔2.1解析2.2题解 3.合并两个有序链表3.1解析3.2题解 4.翻转链表4.1解析4…

人类连接的桥梁:探索Facebook如何连接世界

随着技术的发展和全球化的进程&#xff0c;我们的世界正在变得越来越紧密相连。在这个过程中&#xff0c;社交媒体平台扮演了一个至关重要的角色&#xff0c;为人们提供了一个跨越国界、文化和语言的交流平台。其中&#xff0c;Facebook作为全球最大的社交媒体平台&#xff0c;…

rancher踩坑日志:prometheus访问kubelet 10250端口提示鉴权失败

该原因是因为kubectl禁止了非授权用户访问10250端口来获取node的数据。 解决思路&#xff1a; 添加prometheus访问kubelet时带上证书进行验证匹配 --> 由于我的prometheus是rancher安装的&#xff0c;不知道要怎么修改所以研究了一会没研究明白就放弃了。设置prometheus访问…

如何批量删除不包含指定关键字的数据行?

一、需求 有一个报名表&#xff0c;包括年龄&#xff0c;地址&#xff0c;特长等数据&#xff0c;现在想删除特长一列中不含“篮球”这个关键字行&#xff0c;可以使用这些办法。 二、删除数据 方法1.自动筛选&#xff0c; 1.1 选中数据后&#xff0c;点击数据选项卡&#…

微信人脉扩张!多号批量自动加好友,你get到了吗?

微信是我们在拓展社交圈和寻找商业机会时&#xff0c;与更多的人建立联系的重要渠道。但是&#xff0c;手动一个个添加好友显然费时费力&#xff0c;这时候&#xff0c;微信管理系统的批量自动加好友功能就成为了微信人脉扩张的神器。 通过微信管理系统&#xff0c;我们可以轻…

IO流-打印流

简介 为打印而生的IO流 打印流的继承体系 优点 高效方便打印的是啥就是啥&#xff0c;不会瞎转&#xff08;不会把97转成a&#xff09; PrintStream try(PrintStream ps new PrintStream("test7.txt", "UTF-8"); ){ps.println(97); // 打印流的优点就是原…

三个晚上!给干废了!MINI2440 挂载 NFS

虚拟机执行&#xff1a;sudo ifconfig tap0 10.10.10.1 up qemu 开发板&#xff1a; set bootargs noinitrd root/dev/nfs rw nfsroot10.10.10.1:/nfsroot ip10.10.10.10:10.10.10.1 ::255.255.255.0 consolettySAC0,115200 Hit any key to stop autoboot: 0 MINI2440 # set…

前后端分离vue.js+nodejs新闻文章发布论坛网站系统44x94

Vue&#xff1a; Vue是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库或既有项目整合。另一方面&#xff0c;当与现代化的工具链以及…

​代码混淆的原理是什么?常见代码混淆方法介绍

本文主要想你介绍代码混淆的原理&#xff0c;常见代码混淆方法&#xff0c;欢迎查阅~ 移动应用代码安全非常重要&#xff0c;代码逆向会导致代码逻辑被获取&#xff0c;进一步导致控制流被hook&#xff0c;安全防线被破&#xff0c;给APP安全带来巨大风险&#xff0c;因此开发者…

跟着Datawhale重学数据结构与算法

数据结构和算法之前学过&#xff0c;现在跟着Datawhale重学一下&#xff0c;就当是监督自己学习&#xff0c;重新拾起来养成一个好的习惯&#xff0c;以后可以一直坚持下去。 开源链接&#xff1a;【 教程地址 】【电子网站】 首先&#xff1a; #mermaid-svg-Cdr3rn9fGCVAiKS…