我要成为算法高手-双指针篇

目录

  • 什么是双指针?
  • 问题1:移动零
  • 问题2:复写零
  • 问题3:快乐数
  • 问题4:盛最多水的容器
  • 问题5:有效三角形个数
  • 问题6:查找总价格和为目标值的两个商品(两数之和)
  • 问题7:三数之和
  • 问题8:四数之和
  • 总结

什么是双指针?

双指针算法是一种常见的解决问题的技巧,通常使用两个变量在链表或者数组中进行迭代、遍历,从而达到解决问题的目的。光说理论太抽象,我们来几道题目吧~~

问题1:移动零

力扣链接:移动零
在这里插入图片描述
分析一下题目要求: 将给定数组中所有的0移动到数组的末尾,也就是将数组分成两个区域,前半部分是非零元素,后半部分都是零,并且保持非零元素的相对顺序,如示例1,非零元素的顺序:1,3,12,处理之后非零元素的顺序也要是1,3,12,在这里插入图片描述

解题思路:
既然是双指针算法,那我们就定义两个"指针"咯,这里的"指针",我们是指数组下标
定义两个"指针",dest,cur,
dest:已经处理好的区间内,非0元素的最后一个位置
cur:从左往右遍历数组
dest初始为-1,表示刚开始还没非0元素,cur初始为0
在扫描的过程中,一直让数组保持下面这个状态就好了
在这里插入图片描述
图解:
在这里插入图片描述
代码实现:

public void moveZeroes(int[] nums) {//双指针:定义dest和cur,dest初始值为-1//dest的作用:非0元素的最后一个位置,也就是[0,dest]的区间是非0元素//cur的作用:从左往右扫描数组,遍历数组int dest = -1;for (int cur = 0; cur < nums.length; cur++) {if (nums[cur] != 0) {//cur遇到非0元素,先交换dest+1位置和cur位置的元素,再dest++,cur++int tmp = nums[dest + 1];nums[dest + 1] = nums[cur];nums[cur] = tmp;         dest++;}}
}

问题2:复写零

力扣链接:复写零
在这里插入图片描述
分析一下题目要求: 所谓复写,也就是让我们抄一遍数组的内容,遇到非零的直接抄这个数,遇到零抄两遍零,题目要求我们在原数组上进行操作,也就是说不能重新开辟一个新的数组
在这里插入图片描述
解题思路:
先找到最后一个需要被复写的数,然后从后往前进行复写,如果从前往后,后面的数会被覆盖掉。
如何找到最后一个被复写的数?还是利用双指针算法,如图
在这里插入图片描述
根据cur位置的值,判断dest向前走一步还是两步,走完判断dest是否到达结束位置(dest是否>=arr.length-1),如果dest没有到达结束位置,则让cur++。重复上面的步骤,当dest到达最后位置时,cur指向的就是最后一个被复写的数,要注意的是,dest的位置可能是arr.length-1,也可能是arr.length,如果dest=arr.length(如下图),需要处理这个边界问题,
在这里插入图片描述
处理办法:arr[arr.length - 1] = 0;dest -= 2;cur- -;
在这里插入图片描述
接下来就可以从后往前开始复写了,拿下图举例
在这里插入图片描述

代码实现:

    public void duplicateZeros(int[] arr) {int cur = 0;//指向最后一个位置int dest = -1;//dest指结果中,最后需要复写的位置,开始时不知道dest在哪,所以-1//先找到最后一个被复写的数while (cur < arr.length) {if (arr[cur] == 0) {dest += 2;} else {dest++;}if (dest >= arr.length - 1) {break;}cur++;}//边界情况,可能出现:最后要复写两个0,第二个0在arr.length这个位置if (dest == arr.length) {arr[arr.length - 1] = 0;dest -= 2;cur--;}while (cur >= 0) {if (arr[cur] != 0) {arr[dest] = arr[cur];dest--;} else {arr[dest--] = 0;arr[dest--] = 0;}cur--;}}

问题3:快乐数

力扣链接:快乐数
在这里插入图片描述
题目要求:题目让我们判断给定的数是不是快乐数,快乐数:每次都对这个数进行一次操作(让它的值替换为它每一位的数的平方之和),重复这个操作,判断最终结果是不是变成1或者无限循环变不到1
解题思路:有点类似之前写过的判断链表是否成环,题目说明了结果是1或者无限循环,但是其实1也是无限循环,1重复上述操作结果永远都是1,所以我们可以使用快慢指针的思想,当两个指针相遇时,判断两个指针指向的数是不是1即可(如果不熟悉判断链表是否成环,可以看这篇哦链表OJ)
在这里插入图片描述
代码实现:

//返回n的每一位的平方之和
public int func(int n) {int sum = 0;while (n != 0) {int t = n % 10;sum += t * t;n /= 10;}return sum;
}public boolean isHappy(int n) {int fast = func(n);int slow = n;while (fast != slow) {slow = func(slow);fast = func(func(fast));}return fast == 1;
}

问题4:盛最多水的容器

力扣链接:盛最多水的容器
在这里插入图片描述
题目要求: 给定了n条垂线,题目要找出两条线,与X轴构成的容器最多能盛水的容积
解题思路: 容积V = h*w,其中,h指高度,也就是两条线的最短的那条,w指宽度
在这里插入图片描述
如图:
在这里插入图片描述

代码实现

public int maxArea(int[] height) {//根据规律:向内枚举时,要么宽度肯定减小,但是高度只能是不变或减小(木桶效应)int left = 0;int right = height.length - 1;int maxV = 0;int V = 0;while (left < right) {V = (right - left) * Math.min(height[left], height[right]);if (V > maxV) {maxV = V;}//让高度小的移动,高度小也叫说明容积小,不符合要求if (height[left] <= height[right]) {left++;} else {right--;}}return maxV;
}

问题5:有效三角形个数

力扣链接:有效三角形个数
在这里插入图片描述
题目要求:
给定非负整数数组,在数组中挑3个能组成三角形数,求有几种挑法
解题思路:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码实现:

    public int triangleNumber(int[] nums) {// 利用单调性,使用双指针算法int count = 0;int[] ret = nums;Arrays.sort(ret);// 先排个序int flg = ret.length - 1;//固定好flg,表示最大的数while (flg >= 2) {//固定好flg之后,再利用双指针int left = 0;int right = flg - 1;while (left < right) {if (ret[left] + ret[right] > ret[flg]) {count += (right - left);right--;} else {left++;}}flg--;}return count;}

问题6:查找总价格和为目标值的两个商品(两数之和)

力扣链接:查找总价格和为目标值的两个商品
在这里插入图片描述
题目要求: 给定数组和target(题目说明了已经排好序了),求数组中和为target的两个数,以数组的形式返回这两个数即可
解题思路: 定义双指针left,right分别指向第一个和最后一个元素,求两个指针指向的元素之和如果小于target,说明,要大一点!让left++,同理如果大于target,说明要小一点~~,让right–,当两个值等于target,此时可以返回了
代码实现:

    public int[] twoSum(int[] price, int target) {int[] ret = new int[2];//返回的数组//定义双指针left,rightint left = 0;int right = price.length - 1;while (left < right) {int sum = price[left] + price[right];if (sum < target) {left++;} else if (sum > target) {right--;} else {ret[0] = price[left];ret[1] = price[right];break;}}return ret;}

问题7:三数之和

力扣链接:三数之和
在这里插入图片描述
题目要求:
给定整数数组,判断是否存在相加和为0的三个数,这三个数的下标不能重复,也就是说这三个数下标是不一样的,返回所有的三元组,答案不能是重复的三元组
解题思路:
在这里插入图片描述
找到之后left和right继续移动,解决了不漏的问题,能够把所有的三元组都找出来,但是并没有满足题目要求:不能重复,解决办法就是:当找到两个数后,记录left和right的值,left和right跳过重复的数,另外,固定的数a(下标是flg)也要跳过重复的数
代码实现:

    public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);//先排序int flg = 0;//固定一个的数List<List<Integer>> ret = new ArrayList<>();// 返回的Listwhile (flg <= nums.length-2) {//双指针算法,left,rightint left = flg + 1;//左指针int right = nums.length - 1;//右指针int a = nums[flg];//双指针找目标值和为-a的两个数if(a>0) {//小优化,大于0了,后面的都是>0的数,肯定找不到-abreak;}//双指针算法,思路和求两数之和一样while (left < right) {if (nums[left] + nums[right] < (-a)) {left++;} else if (nums[left] + nums[right] > (-a)) {right--;} else {List<Integer> list = new ArrayList<>();list.add(a);list.add(nums[left]);list.add(nums[right]);ret.add(list);//// 找到结果之后,left,right跳过重复元素,避免越界int leftNumber = nums[left];int rightNumber = nums[right];while (nums[left] == leftNumber && left < nums.length - 1) {left++;}while (nums[right] == rightNumber && right > 0) {right--;}}}// flg也要跳过重复的元素,flg不能越界while (nums[flg] == a&&(flg <= nums.length-2)) {flg++;}}return ret;}

问题8:四数之和

力扣链接:四数之和
在这里插入图片描述
题目要求:
在给定数组中,找出4个和为target的数,这四个数的下标不能重复
解题思路:
明白了两数之和跟三数之和后,四数之和的思路就很简单了,先排序,固定一个数a(最左边或者最右边的数,都是一样的),然后在后面的区间按照三数之和的思路:固定一个数b,按照两数之和找出和为target-a-b的两个数
在这里插入图片描述
同样的,left、right、flg1、flg2也要跳过重复的数
代码实现:

    public List<List<Integer>> fourSum(int[] nums, int target) {Arrays.sort(nums);List<List<Integer>> ret = new ArrayList<>();// 返回的Listfor (int i = 0; i < nums.length; ) {//固定数afor (int j = i + 1; j < nums.length; ) {//固定数bint left = j + 1;int right = nums.length - 1;long aim = (long) target - (nums[i] + nums[j]);//a+bwhile (left < right) {if (nums[left] + nums[right] < aim) {left++;} else if (nums[left] + nums[right] > aim) {right--;} else {List<Integer> list = new ArrayList<>();list.add(nums[left]);list.add(nums[right]);list.add(nums[i]);list.add(nums[j]);ret.add(list);//处理细节,去重int leftNumber = nums[left];int rightNumber = nums[right];while (nums[left] == leftNumber && left < nums.length - 1) {left++;}while (nums[right] == rightNumber && right > 0) {right--;}}}j++;while ((j < nums.length - 2) && nums[j - 1] == nums[j]) {j++;}}i++;while ((i < nums.length - 3) && nums[i - 1] == nums[i]) {i++;}}return ret;

总结

遇到数组划分问题(按要求将数组分划分几个区域)或者如果数组存在单调性(有序的)时,我们可以考虑双指针算法~~

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

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

相关文章

私域流量新利器:大模型+智慧客服+知识智能多管齐下,效果倍增!

前言 随着互联网环境的发展&#xff0c;线上市场竞争日益激烈&#xff0c;越来越多的企业开始关注私域流量的运营和管理——将品牌的用户数据在品牌官网、微信公众号、APP等自有平台上进行管理和运营&#xff0c;通过与用户建立深入的关系和互动&#xff0c;提升用户黏性、增强…

LNMP搭建:Linux+Nginx+MySQL+PHP

关闭防火墙和核心防护&#xff0c;使用一台机器Node1搭建LNMP systemctl stop firewalld; setenforce 0 所需源码包&#xff1a;可以去官网下载 编译Nginx 创建/data&#xff0c;在/data/下放源码包 [rootNode1 ~]#:mkdir /data;cd /data 安装依赖包 [rootNode1 data]#:yum …

第一个SpringBoot程序

第一个SpringBoot程序 目录介绍 当我们创建了一个SpringBoot项目之后&#xff0c;会出现如下的目录结构 SpringBoot项⽬有两个主要的⽬录&#xff1a; src/main/java: Java源代码 src/main/resources:为静态资源或配置⽂件&#xff1a; /static&#xff1a;静态资源⽂件夹,⽐…

Spring Cloud Netflix 之 Ribbon

前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff1a;https://www.captainbed.cn/z ChatGPT体验地址 文章目录 前言前言1、负载均衡1.1、服务端负载均衡1.2、客户端负载均衡 2、Ribbon实现服务…

大模型企业落地:制造业可以选择的应用场景

前言 在当今制造业快速发展的背景下&#xff0c;设备稳定运行对于企业的发展至关重要。然而&#xff0c;传统的设备维修模式已无法满足现代企业的需求。为此&#xff0c;引入智能化、数字化的设备维修解决方案成为必然趋势。本文将探讨如何利用大模型技术&#xff0c;构建企业…

智慧工厂人员定位系统的影响与前景展望

随着科技的不断发展&#xff0c;智能制造正在迅速崛起&#xff0c;而智慧工厂人员定位系统作为其中的重要组成部分&#xff0c;正在改变传统制造业的面貌。这一系统通过利用物联网、室内定位等技术手段&#xff0c;能够实时准确地追踪和监控工厂内人员的位置。那么&#xff0c;…

数据采集项目2-业务数据同步

全量同步 每天都将业务数据库中的全部数据同步一份到数据仓库 全量同步采用DataX datax datax使用 执行 python /opt/module/datax/bin/datax.py /opt/module/datax/job/job.json 更多job.json配置文件在&#xff1a; 生成的DataX配置文件 java -jar datax-config-genera…

linux C语言 pthread多线程11错误 卡死

pthread新手坑&#xff0c;跟着网上直接写&#xff0c;pthread_create然后就让函数跑&#xff0c;跑完了直接在函数里面return。这个流程&#xff0c;小测试&#xff0c;一点毛病都没有&#xff0c;跑得贼溜。 但是客户拿去压测七天后&#xff0c;出现卡死的现象。分析后&…

AI图书下载:《ChatGPT打造赚钱机器》

这本书《ChatGPT打造赚钱机器》&#xff08;ChatGPT Money Machine 2024 The Ultimate Chatbot Cheat Sheet&#xff09;是一本全面的指南&#xff0c;旨在帮助读者快速掌握如何利用ChatGPT等人工智能技术创造收益。 以下是各章节内容的总结&#xff1a; **引言** 介绍了人工智…

AI模型部署:Triton+TensorRT部署Bert文本向量化服务实践

前言 本篇介绍以Triton作为推理服务器&#xff0c;TensorRT作为推理后端&#xff0c;部署句嵌入向量模型m3e-base的工程方案和实现&#xff0c;句嵌入模型本质上是Bert结构&#xff0c;本案例可以推广到更一般的深度学习模型部署场景。 内容摘要 推理服务器和推理后端介绍Ten…

个人关于vuex的见解

前言 vuex是什么&#xff1f; Vuex 是 Vue.js 的官方状态管理库&#xff0c;专为 Vue.js 应用程序设计&#xff0c;用于在复杂的前端应用中集中管理状态。 Vuex 的重要性 集中管理&#xff1a;统一存储应用状态&#xff0c;简化复杂应用的状态逻辑。响应式更新&#xff1a;…

PostgreSQL下载地址

下载地址&#xff1a;PostgreSQL: File Browser

AI实践与学习6-RAG流程优化学习

背景 RAG流程很多细节优化点&#xff0c;助力AIGC。 内容 LangChain在RAG功能上的一些能力 多路向量检索 多向量检索器的核心想法是将我们想要用于答案合成的文档与我们想要用于检索的参考文献分开。这允许系统为搜索优化文档的版本&#xff08;例如&#xff0c;摘要&…

欣九康诊疗系统让中医诊所创收不再难

近些年由于国家对中医药的支持政策不断地在推进落实&#xff0c;所以导致中医馆、中医诊所越开越多&#xff0c;再加上各行各业都在向数字化转型&#xff0c;也给中医诊所带来了冲击&#xff0c;所以如何平衡机遇与竞争&#xff0c;实现诊所创收便成了每位中医诊所的负责人所必…

牛客链表刷题(二)

目录 题目一&#xff1a;合并两个有序链表 代码&#xff1a; 题目二&#xff1a;合并k个有序链表 代码&#xff1a; 题目三&#xff1a;判断链表中是否有环 代码&#xff1a; 题目四&#xff1a;链表中环的入口结点 代码&#xff1a; 题目一&#xff1a;合并两个有序链表 代…

卫星通讯助力船舶可视化监控:EasyCVR视频汇聚系统新应用

一、背景 随着科技的不断进步和社会治安的日益严峻&#xff0c;视频监控系统已经成为维护公共安全和提升管理效率的重要工具。传统的视频监控主要依赖于有线传输&#xff0c;但受到地域限制、布线成本高等因素的影响&#xff0c;其应用范围和效果受到一定限制。而卫星通讯传输…

CentOS 7 下gdb任意版本的升级

文章目录 前言查看gdb版本升级步骤 小结 前言 在做项目的过程中&#xff0c;遇到了难缠的bug&#xff0c;使用gdb调试的时候&#xff0c;bt调用堆栈看的一震头疼&#xff0c;于是就想起把gdb升级一下 当前环境&#xff1a;Centos7&#xff0c;gdb&#xff1a;7.6 稍微好看了那…

提醒:网站使用微软雅黑字体的三种方式,两种侵权,一种不侵权。

大家都知道微软雅黑是windows系统的默认字体&#xff0c;但是不知道微软雅黑的版权归属方正字体&#xff0c;而且方正字体仅仅授权了微软在windows系统中使用该字体&#xff0c;脱离了windows使用&#xff0c;那是极易中招的&#xff0c;网页字体使用是前端开发的工作之一&…

Makefile-快速掌握

引用 本文完全参照大佬的文档写的&#xff0c;写这篇文章只是为了梳理一下知识 https://github.com/marmotedu/geekbang-go/blob/master/makefile/Makefile%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86.md 介绍 Makefile是一个工程文件的编译规则&#xff0c;描述了整个工程的编译…

Netflix 机器学习科学家的提示词优化经验分享

编者按&#xff1a; 如何充分发挥大模型的潜能&#xff0c;用好大模型&#xff0c;关键在于如何优化向它们发送的提示词&#xff08;prompt&#xff09;&#xff0c;是为提示词工程&#xff08;prompt engineering&#xff09;。 本文Netflix 机器学习科学家Cameron R. Wolfe的…