【刷题笔记】两数之和II_二分法||二分查找||边界||符合思维方式

两数之和II_二分法||二分查找

1 题目描述

https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/

给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

2 思路

看到这一个题目,数组和有序,第一个想法就是二分查找(当然看了官方题解之后,发现还有双指针做法)。

做法很简单,给定了target,我们对数组numbers进行遍历,对于numbers的每一个元素,重新在数组中寻找和该元素之和为target的元素。如果找到的元素和遍历到的元素重复了,那么继续遍历,然后再寻找;如果不重复,那就将两个元素的位置都加一获得真实位置,然后返回。

public int[] twoSum(int[] numbers, int target) {int pre = 0;for (int i = 0; i < numbers.length; i++) {if (i > 0 && numbers[i] == pre) // 如果遇到重复元素,就别浪费这个时间了。continue;int other_tar = target - numbers[i];int pos = biSearch(numbers, other_tar);if (pos >= 0) {if (pos == i) continue; // 防止找到自己头上, 比如参数是([0,4,5], 8), 就有会找到两个4。return new int[]{i + 1, pos + 1}; // 索引+1变成真实位置。}pre = numbers[i]; // 记录前一个值}return null;
}

那么最重要的问题是,如何进行二分查找?

我们就事论事,如何分析这个题目呢?

相似题目可以看我的这篇文章【刷题笔记】H指数||数组||二分查找的变体

题目本身已经强调了,非递减顺序,也就是说,数组中可能会存在一些相等的元素。举个例子

towSum([1,3,4,4], 8)

当我们遍历到第一个4的时候,为了让和为8,我们需要在数组中找到另一个为4的元素。如果二分是普通的二分查找:

 if (numbers[mid_index] == num) {return mid_index;}
else if (numbers[mid_index] < num) l = real_mid + 1;
else r = real_mid - 1;

我们极有可能在碰到第一个4的时候,就返回了其坐标,而这和我们题目中的要求是冲突的。那么我们就会接着遍历numbers数组,碰到第二个4,然后继续进行二分查找,找到了第一个4,返回位置,发现这个组合是符合要求的,最后我们返回的两个位置是[4,3]。我替你们试过了,就算你返回的的两个坐标是对的,还是要保证坐标是从小到大的,反过来也会报错。

怎么解决这种存在多个相等元素的问题呢?我的解决方法是分成两步:

  1. 遍历numbers的时候,遇到重复元素,只遍历第一个。上面代码中的:
 if (i > 0 && numbers[i] == pre) // 如果遇到重复元素,就别浪费这个时间了。continue;

就是解决这个问题的。

  1. 在二分查找的时候,只找重复元素的最后一个。这样假设碰到多个重复元素,而且恰好两个重复元素之和等于我们target的情况,最终返回的坐标一定是递增顺序的。

那么我们接下来考虑,怎么在二分查找的时候,找到最后一个符合条件的元素呢?

对于二分查找有两个最重要的问题:如何计算mid如何跳转left和right

我在【刷题笔记】H指数||数组||二分查找的变体这篇博客中提出了一个思考的范式:

这个两个问题本身是一个问题,只要我们确定了如何跳转left和right,就能确定如何计算mid。

(这只是我的一点浅薄的看法,大家要根据自己的刷题情况实时更新自己的理念,我考虑出来的东西也不一定具有普适性,我只是刚刷题的菜鸡。)

怎么理解上面这句话呢?比如我们这道题,我们确定了目标是寻找满足条件(即等于other_tar)的最后一个元素,也就是右边界,一个很符合直觉的想法就是,left指针是不断右移的,要找右边界,left指针最合适。

在这里插入图片描述

那么我们看到,当遇到这种情况的时候,numbers[mid]==other_tarmid可能是右边界吗?可能。那mid右边的位置还可能是右边界吗?不一定。如果left移动到mid右边,会不会错过右边界?可能会。所以,为了避免这种跳过边界的可能性,当mid满足条件的时候,我们不是直接返回mid,而是让left转移到mid的位置上,通过left不断寻找右边界。而当numbers[mid] < other_tar的时候,让left++;当numbers[mid] > other_tar的时候,right--,这些都是常规操作了。

也就是说,当查找边界的时候,我们的left指针最后可能会指向边界。为什么是可能?因为数组里可能没有我们要找的值,这时候left一路向右,势不可挡,直接窜到了数组的边界之外,也是可能的。

现在我们解决了第二个问题,如何跳转left和right。那么我们回过头解决第一个问题,如何计算mid

第二个问题,我们可以直接考虑在只剩下两个元素的时候(即只剩下left和right的时候),该如何计算mid

在这里插入图片描述

众所周知,当我们在只剩下两个元素的时候,mid元素要么是(left + right) / 2,放在left上,要么是(left + right) / 2 + 1,放在right上。

我们已经确定了,left在某些条件下是可能直接跳转到mid上的, 如果让mid=left,下一步如果left需要跳转,left=mid,然后mid=left。。。。。。无限循环。

所以,为了避免死循环,当只有偶数个元素的时候,我们需要让mid跳转到中间两个元素的后一个元素上。所以我说,当我们确定了leftright的跳转问题之后,如何计算mid的问题就迎刃而解。

当然,传统的二分法,left跳转到mid+1,right跳转到mid-1,不会出现死循环的。咱们现在讨论的是边界问题,所以有些特殊。

我还是那句话,我花生豆大的小脑仁接受不了太多弯弯绕绕,面对二分问题的时候,left和right的取值,我倾向于直接使用真实位置,即从1开始的位置。

public int biSearch(int[] numbers, int num) {int l = 1, r = numbers.length;...
}

这样有一个好处就是符合我们的思维直觉,本身二分法的变化就多,能简化思考的地方就简化思考。

那么如果l~r范围内(闭区间)的元素个数是奇数个,(l+r)/2就是中间数的真实位置,如果是偶数个,我们就设为(l+r)/2 + 1。这个方法虽然笨,但是符合我们的思维直觉。

 public int biSearch(int[] numbers, int num) {int l = 1, r = numbers.length;while (l < r) { // 一旦两个指针重合,遍历结束,要么是找到了,要么是l跳到边界外了。int real_mid = (l + r) / 2 + ((l - r + 1) % 2 == 0 ? 1 : 0);int mid_index = real_mid - 1;if (numbers[mid_index] == num) l = real_mid;else if (numbers[mid_index] < num) l = real_mid + 1;else r = real_mid - 1;}if (l <= numbers.length && numbers[l-1] == num) return l-1;else return -1;
}

在这里,所有的指针我都使用了真实值,只有在用到numbers[mid_index]的时候,才用的索引。当然,这些都是我自己的习惯。

因为我们是用left指针来判断边界,left在跳转的过程中,我们计算mid的时候是选择了靠右型,如果left跳转到mid+1的位置,可能跳出边界。

所以我们最后的判断条件是if (l <= numbers.length && numbers[l-1] == num) return l-1;
返回索引。

3 代码

class Solution {public int[] twoSum(int[] numbers, int target) {int pre = 0;for (int i = 0; i < numbers.length; i++) {if (i > 0 && numbers[i] == pre)continue;int other_tar = target - numbers[i];int pos = biSearch(numbers, other_tar);if (pos >= 0) {if (pos == i) continue;return new int[]{i + 1, pos + 1};}pre = numbers[i];}return null;}public int biSearch(int[] numbers, int num) {int l = 1, r = numbers.length;while (l < r) {int real_mid = (l + r) / 2 + ((l - r + 1) % 2 == 0 ? 1 : 0);int mid_index = real_mid - 1;if (numbers[mid_index] == num) l = real_mid;else if (numbers[mid_index] < num) l = real_mid + 1;else r = real_mid - 1;}if (l <= numbers.length && numbers[l-1] == num) return l-1;else return -1;}
}

在这里插入图片描述

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

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

相关文章

统信UOS 1060操作系统上更新系统

往期好文&#xff1a;统信UOS/麒麟KYLINOS禁用USB存储 hello&#xff0c;大家好啊&#xff01;在数字化时代&#xff0c;操作系统的安全性和稳定性对我们的日常工作和生活至关重要。今天&#xff0c;我要给大家介绍的是关于在统信UOS 1060操作系统上&#xff0c;如何通过控制中…

Facebook广告投放效果不佳?这些投放技巧我不允许你不知道!

众所周知&#xff0c;Facebook广告对于跨境卖家来说是非常有效的站外引流渠道&#xff0c;通过Facebook广告投放可以提高跨境卖家的产品销量和排名&#xff0c;但是有时明明广告已经投放出去了&#xff0c;却无法被受众看到&#xff0c;完全没有获得成果&#xff0c;或许你会怪…

CRM系统的数据分析和报表功能对企业重要吗?

竞争日益激烈&#xff0c;企业需要更加高效地管理客户关系&#xff0c;以获取更多的商机。为此&#xff0c;许多企业选择使用CRM系统。在CRM中&#xff0c;数据分析功能扮演着重要的角色。下面就来详细说说&#xff0c;CRM系统数据分析与报表功能对企业来说重要吗&#xff1f; …

pandas(八)--实战一下

背景 收到一批数据&#xff0c;数据形式。采集数据的间隔时间是10分钟&#xff0c;全天采集数据&#xff0c;每天的数据量是144条 处理后的数据形式 分析 去除表格中的q的异常值&#xff0c;置为0去除重复行将原始表格中的date分裂成日期和时间缺失的时间点数据补0&#x…

Unity C++交互

一、设置Dll输出。 两种方式&#xff1a; 第一&#xff1a;直接创建动态链接库工程第二&#xff1a;创建的是可执行程序&#xff0c;在visual studio&#xff0c;右键项目->属性(由exe改成dll) 二、生成Dll 根据选项Release或Debug&#xff0c;运行完上面的生成解决方案后…

如何修改Window电脑的远程登陆端口

主要步骤如下&#xff1a; 1、找到运行对话框&#xff0c;一种方法是&#xff1a;开始->附件->运行&#xff1b;另外一种是快捷键winR组合键。 2、Regedit&#xff0c;在对话框中输入regedit命令&#xff0c;然后回车。备份注册表。手动备份注册表 2.1选择“ 开始 ”&am…

如何使用 CSS columns 布局来实现自动分组布局?

最近在项目中碰到这样一个布局&#xff0c;有一个列表&#xff0c;先按照 4 2 的正常顺序排列&#xff0c;当超过 8 个后&#xff0c;会横向重新开始 4 2 的布局&#xff0c;有点像一个个独立的分组&#xff0c;然后水平排列&#xff0c;如下 图中序号是 dom 序列&#xff0c;所…

【算法心得】When data range not large, try Bucket sort

https://leetcode.com/problems/maximum-number-of-coins-you-can-get/description/?envTypedaily-question&envId2023-11-24 I solve this problem by sorting piles first, and choose piles for(let i1;i<(piles.length/3)*2;i2) but: o(≧口≦)o Problem must …

ISCTF2023新生赛Misc部分WP

ISCTF2023新生赛部分WP MISC&#xff1a;签到&#xff1a;你说爱我&#xff1f;尊嘟假嘟&#xff1a;小蓝鲨的秘密&#xff1a;easy_zip:杰伦可是流量明星&#xff1a;蓝鲨的福利&#xff1a;Ez_misc:PNG的基本食用:小猫&#xff1a;MCSOG-猫猫&#xff1a;镜流:stream&#xf…

基于OpenCV的手势识别系统设计与开发

摘要 随着计算机技术与信息处理技术迅速发展&#xff0c;智能化电子设备逐渐进入到日常的生产和生活中&#xff0c;与此同时&#xff0c;人们对电子设备操作过程的便捷化也提出了新的要求&#xff0c;这也促使计算机进行图像处理的技术也得到了发展。近些年兴起的模式识别技术…

1.自动化运维工具Ansible的安装

1.物料准备 四台服务器&#xff0c;其中一个是主控机&#xff0c;三个为host 2.安装 在主控机上安装ansible 2.1 设置EPEL仓库 Ansible仓库默认不在yum仓库中&#xff0c;因此我们需要使用下面的命令启用epel仓库。 yum install epel-release -y2.2 执行安装命令 yum i…

网站上https协议,nginx配置SSL,443端口

nginx配置ssl 要给自己的网站上ssl证书&#xff0c;使用https协议。首先你需要有证书文件&#xff0c;这个文件是你买的服务&#xff0c;买过之后别人会给你。 就是这样的文件&#xff1a; 然后你就把文件上传到服务器的一个位置&#xff0c;你记住这个位置&#xff0c;后面配…

java审计之java反序列化-CC链

介绍 序列化的本质是内存对象到数据流的一种转换&#xff0c;我们知道内存中的东西不具备持久性&#xff0c;但有些场景却需要将对象持久化保存或传输。 在Java工程中&#xff0c;序列化还广泛应用于JMX&#xff0c;RMI&#xff0c;网络传输&#xff08;协议包对象&#xff09…

Java-MyBatis

1.基础 1.1 pom <dependencies><!--MyBatis核心--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version></dependency><!--MySql驱动--><dependency&…

看看京东的接口优化技巧,确实很优雅!!

大家好&#xff0c;最近看到京东云的一位大佬分享的接口优化方案&#xff0c;感觉挺不错的&#xff0c;拿来即用。建议收藏一波或者整理到自己的笔记本中&#xff0c;随时查阅&#xff01; 下面是正文。 一、背景 针对老项目&#xff0c;去年做了许多降本增效的事情&#xf…

10分钟的时间,带你彻底搞懂JavaScript数据类型转换

前言 &#x1f4eb; 大家好&#xff0c;我是南木元元&#xff0c;热衷分享有趣实用的文章&#xff0c;希望大家多多支持&#xff0c;一起进步&#xff01; &#x1f345; 个人主页&#xff1a;南木元元 目录 JS数据类型 3种转换类型 ToBoolean ToString ToNumber 对象转原…

token认证机制,基于JWT的Token认证机制实现,安全性的问题

文章目录 token认证机制几种常用的认证机制HTTP Basic AuthOAuthCookie AuthToken AuthToken Auth的优点 基于JWT的Token认证机制实现JWT的组成认证过程登录请求认证 对Token认证的五点认识JWT的JAVA实现 基于JWT的Token认证的安全问题确保验证过程的安全性如何防范XSS Attacks…

循环神经网络RNN

1. 背景 RNN(Recurrent Neural Networks) CNN利用输入中的空间几何结构信息&#xff1b;RNN利用输入数据的序列化特性。 2. SimpleRNN单元 传统多层感知机网络假设所有的输入数据之间相互独立&#xff0c;但这对于序列化数据是不成立的。RNN单元用隐藏状态或记忆引入这种依赖…

CSS特效022:小球抛物线效果

CSS常用示例100专栏目录 本专栏记录的是经常使用的CSS示例与技巧&#xff0c;主要包含CSS布局&#xff0c;CSS特效&#xff0c;CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点&#xff0c;CSS特效主要是一些动画示例&#xff0c;CSS花边是描述了一些CSS…

open3d-点云及其操作

open3d提供了一个专门用于点云的数据结构 PointCloud。 class PointCloud(Geometry3D):color # 颜色normals # 法向量points # 点云def __init__(self, *args, **kwargs):"""__init__(*args, **kwargs)Overloaded function.1. __init__(self: open3d.cpu.py…