当前位置: 首页 > article >正文

双指针算法(部分例题解析)

快慢指针+左右指针


前言

双指针,它通过设置两个指针来遍历数据,从而实现高效的查找、排序、去重等操作。双指针算法的核心在于通过合理地移动这两个指针,减少不必要的遍历,提高算法的效率。


283. 移动零 - 力扣(LeetCode)283. 移动零 - 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1:输入: nums = [0,1,0,3,12]输出: [1,3,12,0,0]示例 2:输入: nums = [0]输出: [0] 提示: * 1 <= nums.length <= 104 * -231 <= nums[i] <= 231 - 1 进阶:你能尽量减少完成的操作次数吗?https://leetcode.cn/problems/move-zeroes

知识点:在数组中,我们是利用数组下标来充当指针的。指针目的是锁定某个值,在数组中,下标,1.同样可以锁定值

这跟那个快速排序的前后指针相似,不过这里dest指向cur的后面,而在快速排序中cur在prev的前面,这里就是cur在dest的前面

 让dest一开始为-1,因为cur要从第一个元素开始判断,那你dest只能放在cur到后面那就是负一

void Swap(int *q,int *p)
{int tmp=*q;*q=*p;*p=tmp;
}
void moveZeroes(int* nums, int numsSize) {int dest=-1;for(int cur=0;cur<numsSize;cur++){if(nums[cur]){Swap(&nums[++dest],&nums[cur]);}}
}


1089. 复写零 - 力扣(LeetCode)1089. 复写零 - 给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。 示例 1:输入:arr = [1,0,2,3,0,4,5,0]输出:[1,0,0,2,3,0,0,4]解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]示例 2:输入:arr = [1,2,3]输出:[1,2,3]解释:调用函数后,输入的数组将被修改为:[1,2,3] 提示: * 1 <= arr.length <= 104 * 0 <= arr[i] <= 9https://leetcode.cn/problems/duplicate-zeros

由于0要写两次,所以,找到复写零后面末尾的元素是谁,就是0复写了,以后数组末尾的数字是谁,在这个数字后面的数字就不重要了,我们可以从后往前完成复写,让需要保留的数字,覆盖到不需要保留的数字上。

所以要先找到最后一个复写的数

第一步,先判断cur的位置
第二步,决定dest是向前走一步,还是两步
第三步,判断dest是否已经结束
第四步,cur++

 但是还有一种情况就是当,复写零最后一个结尾数字是0的时候dest走两步已经走到数组外了,还没有判断的机会就出界了,所以要多加一个判断

void duplicateZeros(int* arr, int arrSize) {int cur=0,dest=-1;//让dest=-1,这样就能做到,cur不是0 ,dest就在这一步,如果是0的话,dest就要比cur多走一步,最终有几个零就多走了几步while(cur<arrSize){if(arr[cur]==0)dest++;dest++;if(dest>=arrSize-1)//确定边界,当dest走到size-1的时候就已经找到了边界,也就是最后一个元素,这时我们就跳出循环,当然也有可能他超出了边界break;cur++;}if(dest!=arrSize-1)//如果dest出界了,我们就让dest到n- 1的位置上去,也可以直接写成: n-1=0,dest-=2;cur-=1{arr[arrSize-1]=0;cur--;dest-=2;}while(cur>=0){if(arr[cur])arr[dest--]=arr[cur--];else{if(dest-1>=0)arr[dest--]=0;if(dest-1>=0)arr[dest--]=0;cur--;}}
}

 可以联想一道题:a数组是升序的,b数组也是升序的,a数组里面的长度特意扩大了,数组长度确保能够容纳b,就是要让我们把a,b数组以升序的方式写进a中,他的方法也是从尾部开始比较,大的插入


202. 快乐数 - 力扣(LeetCode)202. 快乐数 - 编写一个算法来判断一个数 n 是不是快乐数。「快乐数」 定义为: * 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 * 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。 * 如果这个过程 结果为 1,那么这个数就是快乐数。如果 n 是 快乐数 就返回 true ;不是,则返回 false 。 示例 1:输入:n = 19输出:true解释:12 + 92 = 8282 + 22 = 6862 + 82 = 10012 + 02 + 02 = 1示例 2:输入:n = 2输出:false 提示: * 1 <= n <= 231 - 1https://leetcode.cn/problems/happy-number

 攻破点:一个正整数,一直这样下去会循环下去,也就是会出现两个重复的数字,会形成一个圈,一直在圈里面打转,如果说在这个过程中出现的一个结果是1,但还不是会无限循环下去,所以无论是快乐树,还是不快乐数,最后都会循环成环,只不过在,快乐数中,环中的数字都是1

在链表中,有一道题是判断链表是否成环,还有一道题是返回链表成环的起始位置,那两道题中,我们都用到了快慢指针,所以这道题也可以用快慢指针


快慢指针:

快指针和慢指针从同一个起点开始。快指针每次移动两步,慢指针每次移动一步

快指针比慢指针快一步,所以他们相对速度是一步,所以如果是有环的话,快指针是一定会追上慢指针的,所以我们这道题的思路是用快慢双指针法,当快慢指针相遇时,看所处的值是不是1

int func(int n)
{int sum=0;while(n){int tmp=n%10;sum+=tmp*tmp;n/=10;}return sum;
}
bool isHappy(int n) {int slow=n;int fast=func(n);while(slow!=fast){slow=func(slow);fast=func(func(fast));}return slow==1;
}


 11. 盛最多水的容器 - 力扣(LeetCode)11. 盛最多水的容器 - 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。说明:你不能倾斜容器。 示例 1:[https://aliyun-lc-upload.oss-cn-hangzhou.aliyuncs.com/aliyun-lc-upload/uploads/2018/07/25/question_11.jpg]输入:[1,8,6,2,5,4,8,3,7]输出:49 解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。示例 2:输入:height = [1,1]输出:1 提示: * n == height.length * 2 <= n <= 105 * 0 <= height[i] <= 104https://leetcode.cn/problems/container-with-most-water

如果按一开始暴力的思路做的话,就定住一个边,然后变化其他的边,然后把面积最大值记录下来,然后再换下一个边,时间复杂度明显是o(n^2), 时间会超

设两指针 i , j ,指向的水槽板高度分别为 h[i] , h[j] ,此状态下水槽面积为 S(i,j) 。由于可容纳水的高度由两板中的 短板 决定,因此可得如下 面积公式 :

S(i,j)=min(h[i],h[j])×(j−i)

他这个就像那个木桶装水一样,一个木桶能装多少水,取决于他最短那个板子长度

定义两个指针在数组的两边计算出它那个面积之后,哪边长度短就移动哪边,让他到下一个数上去,因为如果长度短的不移动,另一边也就是,移动长的,那他之后算下来的面积只有可能小于原来的值,你就好比于你一个木桶的短木板在那里,你周围木板再怎么换,只有可能小于原来装的水的量,跟这个是一个思路,这样时间复杂度就只有o(n)

int minfunc(int q,int p,int gap)//S(i,j)=min(h[i],h[j])×(j−i)
{if(q>=p)return p*gap;elsereturn q*gap;
}
int maxArea(int* height, int heightSize) {int left=0;int right=heightSize-1;int max=minfunc(height[left],height[right],right-left);while(left<right){int tmp=minfunc(height[left],height[right],right-left);if(tmp>max)max=tmp;if(height[left]>height[right])right--;else left++;}return max;
}


611. 有效三角形的个数 - 力扣(LeetCode)611. 有效三角形的个数 - 给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。 示例 1:输入: nums = [2,2,3,4]输出: 3解释:有效的组合是: 2,3,4 (使用第一个 2)2,3,4 (使用第二个 2)2,2,3示例 2:输入: nums = [4,2,3,4]输出: 4 提示: * 1 <= nums.length <= 1000 * 0 <= nums[i] <= 1000https://leetcode.cn/problems/valid-triangle-number

思路:一开始数很乱啊,其次条件符合a+b大于c , b+c大于a , a+c大于b 要判断三次,如果是有序的话,那就只需要两个小的数,大于最大的数即可

 例:2     2     3     4     5     9    10

定义两个指针,left在第一个和right倒数第二,最后一个数字定为max


如果此时left+right是大于max的,那么right和left中间的数字,加上right都会大于max,然后让right-- ,  去找比right小一点的数说,相反,如果不大于的话就要提升left


count就+=(right-left )加上他们中间的数字


等到把10的情况都找到之后,也就是while(left<right)结束后再固定9

int triangleNumber(int* nums, int numsSize) {int gap=numsSize;while(gap>1)//.....Sort{gap/=2;for(int i=0;i<numsSize-gap;i++){int end=i;int tmp=nums[end+gap];while(end>=0&&nums[end]>tmp){nums[end+gap]=nums[end];end-=gap;}nums[end+gap]=tmp;}}int count=0;for(int i=numsSize-1;i>1;i--){int a=0;int b=i-1;while(a<b){if(nums[a]+nums[b]>nums[i]){count+=(b-a);b--;}else{a++;}}}return count;
}

和为S的两个数字_牛客题霸_牛客网输入一个升序数组 array 和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果。题目来自【牛客题霸】https://www.nowcoder.com/share/jump/2494110081745073766147第一步,先将数组排序

第二步,两指针向中间移动

使用双指针指向数组第一个元素和最后一个元素,然后双指针对撞移动,如果两个指针下的和正好等于目标值sum,那我们肯定找到了,如果和小于sum,说明我们需要找到更大的,那只能增加左边的元素,如果和大于sum,说明我们需要找更小的,只能减小右边的元素。

  • 准备左右双指针分别指向数组首尾元素。
  • 如果两个指针下的和正好等于目标值sum,则找到了所求的两个元素。
  • 如果两个指针下的和大于目标值sum,右指针左移;如果两个指针下的和小于目标值sum,左指针右移。
  • 当两指针对撞时,还没有找到,就是数组没有。
int* FindNumbersWithSum(int* array, int arrayLen, int sum, int* returnSize ) {// write code hereint *arr=(int *)malloc(sizeof(int)*2);int left=0;int right=arrayLen-1;while(left<right){if(array[left]+array[right]>sum)right--;else if(array[left]+array[right]<sum)left++;else{arr[0]=array[left];arr[1]=array[right];*returnSize=2;break;}}return arr;}

那如果是三数之和呢?

那就是定第一个数为num,在后面的区间中用二数之和的思路找到和为-num,的两个值

那如果是四数之和呢?

那就是定第一个数为num,后面区间中用三数之和的思度找

总结:

  •  双指针算法通常可以将时间复杂度从 O(n^2) 降低到 O(n) 。例如,在有序数组中查找两数之和,暴力解法需要两层循环,而使用左右指针只需要一层循环。
  • 空间效率高,它不需要额外的存储空间,只需要两个指针变量,空间复杂度一般为 O(1) 。

相关文章:

双指针算法(部分例题解析)

快慢指针左右指针 前言 双指针&#xff0c;它通过设置两个指针来遍历数据&#xff0c;从而实现高效的查找、排序、去重等操作。双指针算法的核心在于通过合理地移动这两个指针&#xff0c;减少不必要的遍历&#xff0c;提高算法的效率。 283. 移动零 - 力扣&#xff08;LeetCo…...

解决Windows打印问题的集成软件

家里或公司电脑经常为连不上打印机而烦恼&#xff0c;今天给大家推荐一款修复打印工具&#xff0c;该工具是采用易语言开发的集成化打印机故障修复软件&#xff0c;专为解决 Windows 系统&#xff08;含 32/64 位 Windows 7/10/11&#xff09;中因权限配置、服务异常、补丁缺失…...

神经网络模型应用到机器学习时的难点

虽然神经网络具有非常强的表达能力&#xff0c;但是当应用神经网络模型到机器学习时依然存在一些难点问题。主要分为两大类: 优化问题&#xff1a;深度神经网络的优化十分困难。 首先&#xff0c;神经网络的损失函数是一个非凸函数&#xff0c;找到全局最优解通常比较困难。 …...

警惕阿里云中的yum update操作不当导致:/sbin/init被清空导致Linux无法正常启动

由于使用阿里云进行部署测试&#xff0c;因而会对yum update进行操作&#xff0c;这两天更新了systemd-239-82.0.3.4.al8.2.x86_64&#xff0c;但存在报错&#xff0c;然后进行yum history undo和清空yum cache&#xff0c;但出现操作Linux命令行无效。具体来说&#xff0c;几个…...

关系型数据库MYSQL(续)

目录 三.MySQL事务原理分析 1.事务是什么&#xff1f; 2.执行事务的目的是什么&#xff1f; 3.事务是由什么组成的&#xff1f; 4.事务的特征是什么&#xff1f; 5.事务控制语句 6.ACID特性 6.1原子性&#xff08;A&#xff09; 6.2隔离性&#xff08;I&#xff09; …...

WInform当今技术特性分析

Windows Forms (WinForms) 技术特性分析 引言 Windows Forms (WinForms) 作为微软最早推出的基于.NET的图形用户界面开发框架&#xff0c;已经存在了20多年。在如今充满了各种现代UI框架的软件开发生态系统中&#xff0c;WinForms仍然保持着其独特的地位。本文将深入分析WinF…...

day46——两数之和-输入有序数组(LeetCode-167)

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

Python 一等函数( 把函数视作对象)

把函数视作对象 示例 5-1 中的控制台会话表明&#xff0c;Python 函数是对象。这里我们创建了一 个函数&#xff0c;然后调用它&#xff0c;读取它的 doc 属性&#xff0c;并且确定函数对象本 身是 function 类的实例。 示例 5-1 创建并测试一个函数&#xff0c;然后读取它的…...

运筹学之模拟退火

目录 一、历史二、精髓思想三、案例与代码实现 一、历史 问&#xff1a;谁在什么时候提出模拟退火&#xff1f;答&#xff1a;模拟退火算法&#xff08;Simulated Annealing&#xff0c;SA&#xff09;是由斯图尔特柯尔斯基&#xff08;Scott Kirkpatrick&#xff09; 等人在 …...

PHP实现简单的爬虫功能

<?php// 目标URL $url https://example.com;// 初始化cURL $ch curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_USERAGENT, Mozilla/5…...

树莓派5-开发应用笔记

0.树莓派系统目录 /home&#xff1a;用户目录。 除了root用户外&#xff0c;其他所有的使用者的数据都存放在这个目录下&#xff0c;在树莓派的系统中&#xff0c;/home目录中有一个pi的子目录,这个就是pi用户的默认目录。 /bin&#xff1a; 主要放置系统的必备执行文件目录。 …...

PostgreSQL 通过 copy 命令导入几何数据 及 通过 CopyManager.copyIn() 导入几何数据

COPY命令介绍 copy是postgresql提供的一个专门用于快速导入导出数据的命令,通常用于从文件(TXT、CSV等)或标准输入输出中读取或写入数据。适合批量导入导出数据,速度快。 默认情况下,如果在处理过程中遇到错误,COPY将失败。 COPY只能用于表,不能用于视图!!! COPY…...

8.5/Q1,Charls最新文章解读

文章题目&#xff1a;Atherogenic index of plasma, high sensitivity C-reactive protein and incident diabetes among middle-aged and elderly adults in China: a national cohort study DOI&#xff1a;10.1186/s12933-025-02653-4 中文标题&#xff1a;中国中老年人群血…...

k8s 调整Node节点 Max_Pods

默认情况下&#xff0c;Kubernetes集群中一个Node最多能起110个Pod。 这是基于性能和资源管理的考虑&#xff0c;以确保Kubernetes集群的稳定性和可靠性。 查看kht125节点上支持的最大pod数量: kubectl describe node kht125 | grep -i “Capacity|Allocatable” -A 6 调整…...

深度补全网络:CSPN++ 有哪些开源项目

关于 ‌CSPN&#xff08;Convolutional Spatial Propagation Network&#xff09;‌ 的开源项目&#xff0c;目前官方或社区维护的完整实现较为有限&#xff0c;但以下资源可作为研究深度补全任务的参考&#xff1a; ‌1. 官方实现 & 相关论文‌ ‌原始论文与代码‌ CSPN 的…...

使用Service发布前后端应用程序

使用Service发布前后端应用程序 文章目录 使用Service发布前后端应用程序[toc]一、创建并发布后端应用程序二、创建并发布前端应用程序三、通过前端发送流量进行测试 部署前端&#xff08;Frontend&#xff09;微服务和后端&#xff08;Backend&#xff09;微服务是比较常见的应…...

Ubuntu20.04下Docker方案实现多平台SDK编译

0 前言 熟悉嵌入式平台Linux SDK编译流程的小伙伴都知道,假如平台a要求必须在Ubuntu18.04下编译,平台b要求要Ubuntu22.04的环境,那我只有Ubuntu20.04,或者说我的电脑硬件配置最高只能支持Ubuntu20.04怎么办?强行在Ubuntu20.04下编译,编又编不过,换到旧版本我又不愿意,…...

-SSRF 服务端请求Gopher 伪协议无回显利用黑白盒挖掘业务功能点

1 、 SSRF 漏洞原理 SSRF(Server-Side Request Forgery: 服务器端请求伪造 ) 一种由攻击者构造形成由服务端发起请求的一个安全漏洞 ; 一般情况下&#xff0c; SSRF 攻击的目标是从外网无法访问的内部系统。 &#xff08;正是因为它是由服务端发起的&#xff0c;所以它能…...

事件冒泡与捕获

一、事件流基础&#xff1a;事件冒泡与捕获的起源 事件流概念 事件发生时在DOM节点上的传播顺序&#xff0c;触发一个节点的事件会连锁触发相关节点的事件。 两种对立模型 事件捕获&#xff08;微软提出&#xff09;&#xff1a;事件从文档根节点&#xff08;如document&#…...

《AI大模型应知应会100篇》第27篇:模型温度参数调节:控制创造性与确定性

第27篇&#xff1a;模型温度参数调节&#xff1a;控制创造性与确定性 摘要 在大语言模型的使用中&#xff0c;“温度”&#xff08;Temperature&#xff09;是一个关键参数&#xff0c;它决定了模型输出的创造性和确定性之间的平衡。通过调整温度参数&#xff0c;您可以根据任…...

聊聊Doris的数据模型,如何用结构化设计解决实时分析难题

传统 OLAP 系统的局限 在大数据实时分析领域&#xff0c;数据模型设计直接决定了系统的查询性能、存储效率与业务适配性。Apache Doris作为新一代MPP分析型数据库&#xff0c;通过独创的多模型融合架构&#xff0c;在业内率先实现了"一份数据支持多种分析范式"的能力…...

LNA设计

设计目的 为后级提供足够的增益以克服后级电路噪声 尽可能小的噪声和信号失真 确保输入和输出端的阻抗匹配 确保信号线性度 评价标准 噪声系数 功率增益 工作频率和带宽 输入信号功率动态范围 端口电压驻波比 稳定性 基于SP模型的LNA设计 直流分析 S参数分析 设计指标 &#xf…...

小红书爬虫,小红书api,小红书数据挖掘

背景&#xff1a; 小红书&#xff08;Xiaohongshu&#xff09;是一款结合社交、购物和内容分享的移动应用&#xff0c;近年来在中国以及全球范围内拥有大量的用户群体。小红书上的内容包括用户的消费体验、生活方式、旅行分享、时尚搭配等。通过这些内容&#xff0c;用户可以了…...

C++ STL 环形队列模拟实现

C STL 环形队列模拟实现 下面是一个使用C STL实现的环形队列&#xff08;Circular Queue&#xff09;的完整示例&#xff1a; #include <iostream> #include <vector> #include <stdexcept>template <typename T> class CircularQueue { private:std…...

C++中unique_lock和lock_guard区别

目录 1.自动锁定与解锁机制 2.灵活性 3.所有权转移 4.可与条件变量配合使用 5.性能开销 在 C 中&#xff0c;std::unique_lock 和 std::lock_guard 都属于标准库 <mutex> 中的互斥锁管理工具&#xff0c;用于简化互斥锁的使用并确保线程安全。但它们存在一些显著区别…...

Vue 3 组合式 API 规范配合 Pinia

实现效果&#xff1a; 根据pinia中存储的不同状态&#xff0c; 点击不同的按钮&#xff0c;切换不同的弹窗和标题1. Pinia Store&#xff08;组合式写法&#xff09; // stores/dataStore.ts import { defineStore } from pinia import { reactive } from vuetype DialogType …...

JavaSpring 中使用 Redis

创建项目 配置 Redis 服务地址 创建 Controller 类 由于当前只是些简单的测试代码&#xff0c;所以就不进行分层了&#xff0c;只创建一个 Controller 来实现 jedis 通过 jedis 对象里的各种方法来操作 Redis 此处通过 StringRedisTemplate 来操作 Redis 最原始提供的类是 Re…...

多线程使用——线程安全、线程同步

一、线程安全 &#xff08;一&#xff09;什么是线程安全问题 多个线程&#xff0c;同时操作同一个共享资源的时候&#xff0c;可能会出现业务安全的问题。 &#xff08;二&#xff09;用程序摹拟线程安全问题 二、线程同步 &#xff08;一&#xff09;同步思想概述 解决线…...

Spring Boot 集成 tess4j 实现图片识别文本

tesseract是一个开源的光学字符识别&#xff08;OCR&#xff09;引擎&#xff0c;它可以将图像中的文字转换为计算机可读的文本。支持多种语言和书面语言&#xff0c;并且可以在命令行中执行。它是一个流行的开源OCR工具&#xff0c;可以在许多不同的操作系统上运行。 Tess4J是…...

JAVA IO、BIO、NIO、AIO及零拷贝

概述 IO,常写作 I/O,是 Input/Output 的简称,是 Input/Output 的简称,即输入/输出。通常指数据在内部存储器(内存)和外部存储器(硬盘、优盘等)或其他周边设备之间的输入和输出。 目前有三种 IO 共存。分别是 BIO、NIO 和 AIO。 BIO 全称 Block-IO 是一种同步且阻塞的…...