【双指针】N数之和

news/2024/9/17 7:15:51/ 标签: java, 双指针, leetcode

N数之和

  • 两数之和
    • 题目
    • 题目解析
    • 暴力思路
    • 双指针优化
  • 三数之和
    • 题目
    • 题目解析
    • 暴力思路
    • 双指针优化
  • 四数之和
    • 题目
    • 题目解析
    • 暴力思路
    • 双指针优化

两数之和

题目

题目链接: 查找总价格为目标值的两个商品

虽然题目名字不是两数之和, 但是由于和后面的三数之和, 四数之和是连起来的, 于是换一个名字.

正统的两数之和是这个连接: 两数之和, 它的区别是返回的是下标, 而不是数字本身

题目解析

非常容易理解, 就是返回两个数字, 这两个数字的和要是 target

暴力思路

暴力思路也就是经典的枚举出所有的二元组, 依次查看和是否为 target 即可

使用一个简单的双重for循环就可以达到这个效果

java">class Solution {public int[] twoSum(int[] price, int target) {for(int i = 0; i < price.length; i++){for(int j = i + 1; j < price.length; j++){if(price[i] + price[j] == target){return new int[]{price[i] ,price[j]};}}}return null;}
}

但是由于这个题目的数组长度最大是10^5, 因此时间复杂度为O(n^2)的算法是一定会超时的

双指针优化

实际上这一题有一个条件在我们使用暴力解法的时候没有用到, 就是按照升序记录. 也就是说这个数组是已经排好序了, 这是一个非常重要的提示.

此时我们就要想到题目的要求, 实际上是求a + b = target. 那么实际上在暴力枚举的过程中, 就只有三种情况会发生, 分别是a + b > target, a + b < target, a + b = target

那么此时就有一个双指针思路非常适合去一个有序的数组中寻找a + b = target这种情况, 具体步骤如下:

首先先让 left 和 right 指向左侧和右侧, 然后对下列情形分别进行不同操作, 直到left > right

  1. left + right > target, 此时right–
  2. left + right < target, 此时left++
  3. left + right = target, 此时找到答案

此时的这个指针由于两者向内, 因此也有一个特殊的名称叫做对撞指针

那么为什么可以这样操作呢? 实际上这是也是由于有序数组的单调性决定的. 我们使用上面题目的例子来看

在这里插入图片描述

可以看到, 我们要找61, 刚开始left = 8, right = 66.

此时8 + 66 > 61, 很明显此时计算的结果是更大的, 那么此时我们如果要找到61这个值, 就需要让我们的left + right的值变小. 由于数组是有序的, 如果我们想要让left + right 变小, 就只能让 right 往左走了.

下一步到达了8 + 52 < 61, 此时同上, 结果太小, 需要让结果变大, 那么此时就只能让left往右走了.

随后一直循环进行判断, 就会走到left = 27 right = 34 的情况

思路还是较为简单的, 下面就是代码

java">class Solution {public int[] twoSum(int[] price, int target) {// 指向左侧和右侧int left = 0, right = price.length - 1;while(left <= right){// 分别对应三种情况if(price[left] + price[right] > target) right--;else if(price[left] + price[right] < target) left++;else return new int[]{price[left], price[right]};}return null;}
}

三数之和

题目

题目链接: 三数之和

题目解析

题目本身描述的就是找三个数令其和为0, 同时这三个数字不能是同一个. 我们同样可以通过例子来理解

首先看第一个例子, 可以看出实际上就是要你从数组中找三个的数字, 让其和为0. 这三个数字的顺序不重要

在这里插入图片描述

同时我们可以从第二个例子中看出, 他要求的是不同的数, 因为他选不了0 0 0

在这里插入图片描述

暴力思路

这里的暴力思路就和两数之和的一样, 遍历所有三元组. 就是一个三重for循环, 时间复杂度为O(n^3), 这里我们就不书写了

双指针优化

对于这一题, 实际上核心点在于两个: 1. 找三个数 2. 去重

对于第一个点, 我们可以化繁为简. 我们这一题的要求是求出三个数, 令其结果是0. 那么我们是否可以换一种思路, 我们找三个数a b c, 能否去找b + c = -a呢? 答案是当然可以的, 同时求这个b + c = -a的过程, 我们就可以参考两数之和的求解过程. 这种化繁为简, 将难题化为简单的题的思路还是比较常用的.

那么参考两数之和的求解, 首先我们就需要对数组进行排序, 然后从第一个数开始, 把每一个数当为a, 然后在其后方区域进行两数之和的操作. 下面是一个例子

在这里插入图片描述

解决了第一个点, 接下来就是第二个点, 去重. 这里有一个非常简单的方法就是使用自带的集合类去去重, 比如Java中的HashSet. 但是我们这里就不使用这种方法了, 而是使用手动的方式来实现.

上面我们说过, 我们是需要对数组进行排序的, 那么相对应的就是, 相同的数字会在同一个部分, 如下所示

在这里插入图片描述

那么此时我们就可以在过程中, 当当前数字和上一个数字不同的时候, 存储数字, 如果当前数字和上一个数字相同, 那么就跳过这些相同的数字. 但是这里要注意的是, 无论是选择a, 或者是b + c的过程, 都需要跳过相同的数字

这题的思路相较于上面的两数之和还是较为复杂的, 不过根据我们上面的分析, 大致可以分为如下几个步骤:

  1. 对数据进行排序
  2. 使用循环从第一个数字开始往后逐个作为数字 a, 同时需要进行去重
  3. 对 a 后方的数字进行寻找b c 的操作, 使用两数之和的方式寻找, 同时需要进行去重

下面是代码

java">class Solution {public List<List<Integer>> threeSum(int[] nums) {// 对数组进行排序Arrays.sort(nums);// 创建返回值List<List<Integer>> ret = new ArrayList<>();int n = nums.length;// 从第一个数字开始往后循环for(int a = 0; a < n - 2;){// 创建left和right用于执行两数之和int left = a + 1;int right = n - 1;int target = -nums[a];// 执行两数之和while(left < right){int sum = nums[left] + nums[right];if(sum > target) right--;else if(sum < target) left++;else {// 此时找到了一个元组, 放入numsret.add(Arrays.asList(nums[a], nums[left], nums[right]));// 两侧指针向内移动left++; right--;// 去重while(left < right && nums[left] == nums[left - 1]) left++;while(left < right && nums[right] == nums[right + 1]) right--;} }// 对a去重a++;while(a < n - 2 && nums[a] == nums[a - 1]) a++;}return ret;}
}

四数之和

题目

题目链接: 四数之和

题目解析

经历了上面两道题, 这道题也十分好理解, 就是求不同的四个数使其总和为 target

暴力思路

暴力思路也和上面的一样, 经典嵌套for循环, 这里是求4个数那么自然就是四重for循环, 时间复杂度为O(n^4), 这里不再阐述

双指针优化

双指针优化和三数之和的思路一致, 先找一个数, 在后方区间求三数之和, 然后三数之和的思路就和前面一样, 那么总结下来的流程如下

  1. 先排序数组
  2. 使用一个数 a 遍历数组, 设 a 后方区间为[m, n], 那么就是在[m, n]区间内使用三数之和思路寻找 target - nums[a]
  3. 同三数之和思路, 在[m, n]区间内使用一个 b 遍历区间, 同时在 b 后方使用两数之和思路寻找 target - nums[a] - nums[b]
  4. 两数之和思路不在阐述
  5. 中间过程均需要去重

最终代码如下

java">class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {// 排序Arrays.sort(nums);List<List<Integer>> ret = new ArrayList<>();int n = nums.length;// 四数之和for(int i = 0; i < n;){// 三数之和for(int j = i + 1; j < n;){// 两数之和int left = j + 1;int right = n - 1;// 这里使用long是由于恶心人的测试用例long targetTwo = (long)target - nums[i] - nums[j];while(left < right){int sum = nums[left] + nums[right];if(sum > targetTwo) right--;else if(sum < targetTwo) left++;else{// 找到元组, 放入并收缩ret.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));left++;right--;// 去重while(left < right && nums[right] == nums[right + 1]) right--;while(left < right && nums[left] == nums[left - 1]) left++;}}// 去重j++;while(j < n && nums[j] == nums[j - 1]) j++;}// 去重i++;while(i < n && nums[i] == nums[i - 1]) i++;}return ret;}
}

http://www.ppmy.cn/news/1522684.html

相关文章

【持续更新】Adobe Audition 2024 (v24.4.1.003)最新免费修改版

Adobe Audition是一款专为录音、编辑和掌握音频素材设计的专业解决方案。此编辑器支持从MP3、AAC到AIFF等多种重要格式&#xff0c;并能从CD中导入音轨。 其多轨编辑功能使您可以在任意数量的轨道上混合音乐、语音和声音片段&#xff0c;运用丰富的工作室动态效果&#xff0c;如…

nginx配置中的服务器名称

通常&#xff0c;在nginx的配置节中&#xff1a; server {listen 80;server_name example.org www.example.org;... } server_name(服务器名称) 指令定义确定哪个服务器块用于给定请求。可以使用确切名称、通配符名称、ip地址或正则表达式来定义它们&#xff1a; se…

如何在 AWS S3 中设置跨区域复制

如何在 AWS S3 中设置跨区域复制 概述 欢迎来到雲闪世界。 Amazon Simple Storage Service (S3) 是一种可扩展的对象存储服务&#xff0c;广泛用于存储和检索数据。其主要功能之一是跨区域复制 (CRR)&#xff0c;允许跨不同的 AWS 区域自动异步复制对象。此功能对于灾难恢复、…

二手手机回收小程序搭建,小程序功能特点

随着社会生活水平的提高&#xff0c;对手机的更新换代的速度也在逐渐加快&#xff0c;出现了大量的闲置手机&#xff0c;而这也给手机回收市场带来了巨大的发展空间&#xff01; 目前&#xff0c;手机回收市场进入到了发展快速期&#xff0c;吸引了越来越多的企业加入大市场中…

4.7 Sensors -- useScroll

4.7 Sensors – useScroll https://vueuse.org/core/useScroll/ 作用 响应式的监听滚动位置和状态。 官方示例 <script setup lang"ts"> import { useScroll } from vueuse/coreconst el ref<HTMLElement | null>(null) const { x, y, isScrolling…

Spring常用中间件

1. 数据库中间件 &#xff08;1&#xff09;MySQL: 常用的关系型数据库&#xff0c;支持JDBC和JPA。 &#xff08;2&#xff09;PostgreSQL: 功能强大的开源关系型数据库&#xff0c;支持复杂查询。 &#xff08;3&#xff09;MongoDB: NoSQL数据库&#xff0c;适合存储非结构化…

【Rust练习】13.数组

练习题来自&#xff1a;https://practice-zh.course.rs/compound-types/array.html 1 fn main() {// 使用合适的类型填空let arr: __ [1, 2, 3, 4, 5];// 修改以下代码&#xff0c;让它顺利运行assert!(arr.len() 4); }显然这个数组的长度是5. fn main() {// 使用合适的类…

ELK学习笔记(三)——使用Filebeat8.15.0收集日志

使用Filebeat收集日志 前面教程已经把ElasticSearch和Kibana部署完毕&#xff0c;接着我们就要使用filebeat去收集我们的java服务日志&#xff0c;这里首先介绍一下ELK和EFK的区别。 一、ELK和EFK的区别 在收集和处理日志时&#xff0c;使用 ELK&#xff08;Elasticsearch, …

8. GIS数据分析师岗位职责、技术要求和常见面试题

本系列文章目录&#xff1a; 1. GIS开发工程师岗位职责、技术要求和常见面试题 2. GIS数据工程师岗位职责、技术要求和常见面试题 3. GIS后端工程师岗位职责、技术要求和常见面试题 4. GIS前端工程师岗位职责、技术要求和常见面试题 5. GIS工程师岗位职责、技术要求和常见面试…

tabBar设置底部菜单选项以及iconfont图标

tabBartabBar属性:设置底部 tab 的表现 ​ ​ ​ ​ 首先在pages.json页面写一个tabBar对象,里面放入list对象数组,里面至少要有2个、最多5个 tab, 如果只有一个tab的话,H5(浏览器)依然可以显示底部有一个导航栏,如果没有,需要重启后才有,小程序则报错,只有2个以上才可以…

C# 窗口页面布局

1.Groupbox 单机鼠标右键&#xff0c;置于底层 2.Label 在右方属性中修改名称 3.ComboBox 点击属性中的集合&#xff0c;可以添加选择项 4.CheckBox 在属性中修改名称 5.RichTextBox 富文本 在属性中修改名称与区域 6.StatusStrip 状态栏 将AutoSize改成false就可以修改…

基于Java的宿舍报修管理系统的设计与实现(论文+源码)_kaic

基于Java的宿舍报修管理系统的设计与实现(论文源码)_kaic 摘  要 随着教育改革‎‏的不断‎‏深入&#xff0c;‎‏学校宿‎‏舍的管‎‏理体系‎‏也在不‎‏断地完‎‏善&#xff0c;校园后勤服务是学校管理的重要工作&#xff0c;学校提供优秀的后勤服务&#xff0c;能提…

C语言代码练习(第十七天)

今日练习&#xff1a; 45、输出100-1000之间所有的“水仙花数”&#xff0c;所为的水仙花数是一个三位数&#xff0c;其各位数字立方和等于该数本身。例如153是一个水仙花数。因为1*1*15*5*53*3*3 46、一个数如果恰好等于它的因子之和&#xff0c;这个数就称为"完数"…

AI视频百万播放,用这个免费的AI工具,3步教你制作爆款治愈系视频!(附完整教程)

大家好&#xff0c;我是程序员X小鹿&#xff0c;前互联网大厂程序员&#xff0c;自由职业2年&#xff0c;也一名 AIGC 爱好者&#xff0c;持续分享更多前沿的「AI 工具」和「AI副业玩法」&#xff0c;欢迎一起交流~ 今天一位粉丝发了一个视频链接&#xff0c;问这类治愈系风景的…

centos基本命令

当前登录用户&#xff08;root&#xff09; 用户组 其它用户 rwxr-xr-x cd 后加/目录名/子目录 切换到目录 cd .. 切换到父目录 CentOS Windows $>ls 查看某个目录有哪文件和目录 cmd>dir …

机器学习:多种算法处理填充后的数据

在机器学习中&#xff0c;填充数据&#xff08;即处理缺失值&#xff09;后&#xff0c;选择合适的算法并优化模型以提高召回率是一个常见的任务。召回率是指模型正确识别的正例占所有实际正例的比例。 代码思路&#xff1a; 数据预处理&#xff1a; 导入填充后的数据 …

Python | Leetcode Python题解之第386题字典序排数

题目&#xff1a; 题解&#xff1a; class Solution:def lexicalOrder(self, n: int) -> List[int]:ans [0] * nnum 1for i in range(n):ans[i] numif num * 10 < n:num * 10else:while num % 10 9 or num 1 > n:num // 10num 1return ans

太速科技-1路万兆光纤SFP+和1路千兆网络 FMC子卡模块

1路万兆光纤SFP和1路千兆网络 FMC子卡模块 一、概述 该板卡是基于kc705和ml605的fmc 10g万兆光纤扩展板设计&#xff0c;提供了1路万兆光纤SFP和1路千兆网络接口。可搭配我公司开发的FPGA载卡使用。载卡可参考&#xff1a;ID204 SFP&#xff08;10 Gigabit Small…

1-10 图像增强对比度 opencv树莓派4B 入门系列笔记

目录 一、提前准备 二、代码详解 enhanced_image cv2.convertScaleAbs(image, alpha1.5, beta0) 三、运行现象 四、完整工程贴出 一、提前准备 1、树莓派4B 及 64位系统 2、提前安装opencv库 以及 numpy库 3、保存一张图片 二、代码详解 import cv2 # 增强图像的对比度 …

【Arm Cortex-X925】 -【第五章】-电源管理

5. 电源管理 Cortex-X925 核心提供了控制动态和静态功耗的机制。 动态功耗管理包括以下特性: 层次时钟门控每核心的动态电压和频率调整 (DVFS)静态功耗管理包括以下特性: 关机模式动态保持,一种低功耗模式,能够保留寄存器和 RAM 状态5.1 电压和功率域 DynamIQ™ Shared …