【leetcode】双指针算法题

文章目录

  • 1.算法思想
  • 2.移动零
  • 3.复写零
    • 方法一
    • 方法二
  • 4.快乐数
  • 5.盛水最多的容器
    • 方法一(暴力求解)
    • 方法二(左右指针)
  • 6.有效三角形的个数
    • 方法一(暴力求解)
    • 方法二(左右指针)
  • 7.两数之和
  • 8.三数之和
  • 9.四数之和

在这里插入图片描述

1.算法思想

常见的双指针有两种形式,⼀种是左右指针,⼀种是快慢指针。

  1. 左右指针:⼀般用于有序的结构中,也称左右指针。
  • 左右指针从两端向中间移动。⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼近。
  • 左右指针的终⽌条件⼀般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循环),也就是:
    left == right (两个指针指向同⼀个位置)
    left > right (两个指针错开)
  1. 快慢指针:⼜称为龟兔赛跑算法,其基本思想就是使⽤两个移动速度不同的指针在数组或链表等序列结构上移动。
    这种方法对于处理环形链表或数组非常有用。
    其实不单单是环形链表或者是数组,如果研究的问题出现循环往复的情况时,均可考虑使用快慢指针的思想。
    快慢指针的实现⽅式有很多种,最常用的⼀种就是:
  • 在⼀次循环中,每次让慢的指针向后移动⼀位,而快的指针往后移动两位,实现⼀快⼀慢。

废话不多说,我们来做题。

2.移动零

在这里插入图片描述
leetcode 283.移动零

题目要求我们将数组中的0全部移动到数组的末尾,并且其它元素的相对顺序不变而且不允许开辟额外的数组
那我们应该如何来解决这一题呢?

算法思路:
在本题中,我们可以⽤⼀个cur 指针来扫描整个数组,另⼀个dest 指针⽤来记录⾮零数序列的最后⼀个位置。
根据cur 在扫描的过程中,遇到的不同情况,分类处理,实现数组的划分。
在cur遍历期间,使[0, dest] 的元素全部都是⾮零元素,[dest + 1, cur - 1] 的元素全是零

最初,我们不知道非零序列的位置,所以将dest置为-1,cur置为0。cur进行扫描,在扫描过程中:

  • 若cur对应元素不为0,cur后移
  • 若cur对应元素为0,dest先后移,然后再交换cur与dest,最后cur再后移。

在这里插入图片描述

class Solution {
public:void moveZeroes(vector<int>& nums) {int dest = -1;int cur = 0;int n = nums.size();while(cur < n){//cur不为0,交换if(nums[cur] != 0){dest++;swap(nums[dest],nums[cur]);}//cur为0,继续后移cur++;}}
};

这样咱们就过啦。
在这里插入图片描述

3.复写零

在这里插入图片描述
leetcode 1089.复写零

方法一

先统计数组中0的个数,计算复写后数组的大小,使用reserve为数组重新开新的空间,在新空间上直接进行复写,不存在数组越界问题;在复写完成后,再使用对数组进行缩容,使其空间保持原状。

class Solution {
public:void duplicateZeros(vector<int>& arr) {int count = 0;int n = arr.size();int cur = 0;while(cur < n){if(arr[cur] == 0)count++;cur++;}//开辟新空间arr.reserve(n+count);//此时cur == n,cur--;//重新指向最后一个元素int dest = n+count-1;while(cur >= 0){if(arr[cur]){//不是0,无需复写arr[dest--] = arr[cur--];}else{//复写0arr[dest--] = 0;arr[dest--] = 0;cur--;}}arr.reserve(n);//恢复数组原状}
};

在这里插入图片描述
简单分析一下复杂度:只遍历了数组,时间复杂度为O(N);由于使用了reserve开辟了新空间,空间复杂度:O(N)

方法二

能不能在O(1)的空间复杂度下完成该题呢?

我们可以使用两个指针,cur指向最后一个要写的元素,dest指向数组的最后一个位置。

  • 若cur为0,复写0,dest移动两次
  • 若cur不为0,复写,dest移动一次

那现在的问题就是如何找最后一个要复写的位置。
通过模拟我们可以发现,cur = 0 ,dest = -1;让cur与dest同时走,若cur不为0,则都移动一次;若cur为0,cur移动一次,dest移动两次;直到dest走到数组的末尾,此时cur位置就是最后一个要写的位置

在这里插入图片描述

public:void duplicateZeros(vector<int>& arr) {int cur = 0;int dest = -1;int n = arr.size();while(dest < n-1){if(arr[cur] == 0)dest += 2;elsedest++;cur++;}}for( ; cur >=0; cur--){if(arr[cur])arr[dest--] = arr[cur];else{arr[dest--] = 0;arr[dest--] = 0;}}}
};

在这里插入图片描述
此时我们发现程序没过,情况又没想全

在这里插入图片描述

class Solution {
public:void duplicateZeros(vector<int>& arr) {int cur = 0;int dest = -1;int n = arr.size();while(cur < n){if(arr[cur] == 0)dest += 2;elsedest++;//防止越界if(dest >= n-1)break;cur++;}//已经越界,修正if(dest == n){arr[n-1] = 0;dest-=2;cur--;}//从后向前复写for( ; cur >=0; cur--){if(arr[cur])arr[dest--] = arr[cur];else{arr[dest--] = 0;arr[dest--] = 0;}}}
};

在这里插入图片描述

此时,该代码地时间复杂度为O(N);空间复杂度为:O(1)

4.快乐数

在这里插入图片描述
leetcode 202.快乐数

根据题意,通过画图我们可以发现,这就是一种循环往复地题目。此时我们就可以考虑双指针算法。
在这里插入图片描述
看到这个环形,是不是会想起链表那里有一个判断环形链表的题目,这两题很相似。

我们可以知道,当重复执行x的时候,数据会陷⼊到⼀个「循环」之中。
而「快慢指针」有⼀个特性,就是在⼀个圆圈中,快指针总是会追上慢指针的(证明参考链表部分),也就是说他们总会相遇在⼀个位置上。如果相遇位置的值是1,那么这个数⼀定是快乐数;如果相遇位置不是1的话,那么就不是快乐数。

class Solution {
public:int Sum(int n){int sum = 0;while(n){sum += (n%10)*(n%10);n/=10;}return sum;}bool isHappy(int n) {int slow = n;int fast = Sum(n);//让fast先走一步while(fast != slow){slow = Sum(slow);fast = Sum(Sum(fast));}//当二者相等时,若为1,则是快乐数,否则则不是return slow == 1;}
};

5.盛水最多的容器

在这里插入图片描述
leetcode 11.盛水最多的容器
首先我们要明白,这个容器的容量是:两个柱子之间的距离×两柱中较矮的一个
所以此题我们可以利用双指针,寻找两柱中组成的容器中最大的一个即可。

方法一(暴力求解)

枚举出能构成的所有容器,找出其中容积最大的值。
容器容积的计算⽅式:
设两指针分别指向水槽板的最左端以及最右端,此时容器的宽度为j - i
由于容器的⾼度由两板中的短板决定,因此可得容积公式:v = (j - i) * min( height[i], height[j])

class Solution {
public:int maxArea(vector<int>& height) {int v = 0;int n = height.size();for(int i=0; i<n; i++){for(int j = i+1; j<n; j++){v = max(v,((j-i)*min(height[i],height[j])));}}return v;}
};

在这里插入图片描述

方法二(左右指针)

观察暴力解法以后,我们可以发现一个规律:
当使用最开始的左右区间算出来一个V1后,我们没必要使用这两个区间中较小的一个去和其它数枚举,因为枚举出来的结果一定是小于V1的
在这里插入图片描述
所以,可以按照以下步骤:

  • 先根据当前两柱计算V
  • 舍去两柱子中较小的一个
  • 根据新的柱子再计算体积tmp,V = max(V,tmp)
class Solution {
public:int maxArea(vector<int>& height) {int v = 0;int left = 0;int right = height.size()-1;while(left < right){//先计算当前两柱组成的大小int tmp = (right-left) * min(height[left],height[right]);v = max(v,tmp);if(height[left] < height[right])left++;elseright--;}return v;}
};

6.有效三角形的个数

在这里插入图片描述

leetcode 611.有效三角形的个数

我们都知道,组成三角形的条件是:任意两边之和大于第三边。

方法一(暴力求解)

但是使用这个条件只想到一个暴力解法,虽然说是暴⼒求解,但是还是想优化⼀下
判断三⻆形的优化:

  • 如果能构成三⻆形,需要满⾜任意两边之和要大于第三边。但是实际上只需让较小的两条边之和大于第三边即可
  • 因此我们可以先将原数组排序,然后从小到大枚举三元组,一方面省去枚举的数量,另一方面方便判断是否能构成三⻆形。
class Solution {
public:int triangleNumber(vector<int>& nums) {int n = nums.size();sort(nums.begin(),nums.end());int count = 0;for(int i=0; i<n; i++){for(int j=i+1; j<n; j++){for(int k = j+1; k<n; k++){if(nums[i] + nums[j] > nums[k])count++;}}}return count;}
};

方法二(左右指针)

将数组排序以后我们可以发现,如果我们固定最右侧数为第三条边,就只需使用左右指针找另外两条即可。
而且如果最左侧的数和右侧数加起来已经大于第三边了,那么左侧和右侧之间的数一定大于第三边,无需再枚举。

在这里插入图片描述

class Solution {
public:int triangleNumber(vector<int>& nums) {//先按照升序排序sort(nums.begin(),nums.end());int max = nums.size() - 1;int ret = 0;//至少要存在3条边while(max >= 2){int left = 0;int right = max - 1;while(left < right){if(nums[left] + nums[right] > nums[max]){ret += right - left;right--;}elseleft++;}max--;}return ret;}
};

7.两数之和

在这里插入图片描述
leetcode 179.和为target的两个数

由于该数组是升序的,那么我们可以直接使用双指针,计算左右指针之和

  • 若和小于target,左指针右移
  • 若和大于target,右指针左移

在这里插入图片描述

class Solution {
public:vector<int> twoSum(vector<int>& price, int target) {vector<int> ret;int left = 0;int right = price.size()-1;while(left < right){if(price[left]+price[right] < target)left++;else if(price[left] + price[right] > target)right--;else{break;}}return {price[left],price[right]};}
};

8.三数之和

在这里插入图片描述
leetcode 15.三数之和

这一题和上一题两数之和的解法非常类似,唯一的不同点就是:该题不允许有重复的三元组

  • 先排序
  • 固定一个数aim
  • 使用两数之和法,找和为 - aim 的两个数即可
    • 不漏
      • 找到一个数以后,left++,right- -继续找
    • 去重
      • left 与right均需要去重,如果left++后任然和之前的相同,那就继续++;right同理,仍需要 - -
      • aim去重,如果aim移动后,仍然和上一个相等,那就继续移动

在这里插入图片描述

class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> ret;sort(nums.begin(),nums.end());int n = nums.size();int i = 0;while(i < n){if(nums[i] > 0)//若num对应的都已经大于0,那么left 与right就更大,和不可能为0了break;int aim = -nums[i];//固定一个数,取其相反数int left = i+1;int right = n-1;while(left < right){int sum = nums[left] + nums[right];if(sum > aim)right--;else if(sum < aim)left++;else{ret.push_back({nums[i],nums[left],nums[right]});//避免遗漏,继续找left++;right--;//left,right去重while(left < right && nums[left] == nums[left-1])left++;while(left < right && nums[right] == nums[right+1])right--;}}i++;while(i < n && nums[i] == nums[i-1])i++;}return ret;}
};

9.四数之和

在这里插入图片描述
leetcode 18.四数之和
该题是在三数之和的基础之上的变形。

仍然还是采用上面的做法,

  • 先排序
  • 固定一个数a
  • 利用三数之和,固定一个数b,找和为target - nums[a] - nums[b]的数
    • 不漏
      • 找到一个数以后,left++,right- -继续找
    • 去重
      • left 与right均需要去重,如果left++后任然和之前的相同,那就继续++;right同理,仍需要 - -
      • b去重,如果b移动后,仍然和上一个相等,那就继续移动
      • a去重,如果a移动后,仍然和上一个相等,那就继续移动
class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {sort(nums.begin(),nums.end());vector<vector<int>> ret;int n = nums.size();int a = 0;while(a < n){int b = a+1;while(b < n){long long aim = (long long)target -nums[a] - nums[b];int left = b+1;int right = n-1;while(left < right){if(nums[left] + nums[right] < aim)left++;else if(nums[left] + nums[right] > aim)right--;else{ret.push_back({nums[a],nums[b],nums[left],nums[right]});left++;right--;while(left < right && nums[left] == nums[left-1])left++;while(left< right && nums[right] == nums[right+1])right--;}}b++;while(b < n && nums[b] == nums[b-1])b++;}a++;while(a < n && nums[a] == nums[a-1])a++;}return ret;}
};

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

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

相关文章

CNN文献综述

卷积神经网络&#xff08;Convolutional Neural Networks&#xff0c;简称CNN&#xff09;是深度学习领域中的一种重要模型&#xff0c;主要用于图像识别和计算机视觉任务。其设计灵感来自于生物学中视觉皮层的工作原理&#xff0c;能够高效地处理图像和语音等数据。 基本原理…

UVa1265/LA4848 Tour Belt

UVa1265/LA4848 Tour Belt 题目链接题意分析AC 代码 题目链接 本题是2010年icpc亚洲区域赛大田赛区的F题 题意 给出一个有n个结点m条边的加权无向图G&#xff08;2≤n≤5000&#xff0c;1≤m≤n(n-1)/2&#xff09;&#xff0c;满足如下条件的结点集B&#xff08;2≤|B|≤n&am…

剪画小程序:手机制作音乐串烧,用它,真的很简单!

Hello&#xff0c;大家好呀&#xff0c;我是不会画画的小画。 相伴关注歌手的小伙伴们&#xff0c;上周五的《歌手 2024》第八期大家看了吧&#xff01;那期节目里有好几首歌都让我沉醉其中&#xff0c;像汪苏泷的《听见下雨的声音》、谭维维的《兰花花儿》等等。 为了能让大…

c++之旅第十一弹——顺序表

大家好啊&#xff0c;这里是c之旅第十一弹&#xff0c;跟随我的步伐来开始这一篇的学习吧&#xff01; 如果有知识性错误&#xff0c;欢迎各位指正&#xff01;&#xff01;一起加油&#xff01;&#xff01; 创作不易&#xff0c;希望大家多多支持哦&#xff01; 一,数据结构…

基于docker环境及Harbor部署{很简短一点了,耐心看吧}

用到的环境&#xff1a; docker 、nacos、compose、harbor&#xff08;自行安装 ,以下连接作为参考&#xff09; nacos&#xff1a;史上最全整合nacos单机模式整合哈哈哈哈哈_nacos 源码启动 单机模式-CSDN博客 docker、compose、harbor:史上最全的整合Harbor安装教程&#…

数据结构之顺序表专题

在学习数据结构之前我们要先了解什么是数据结构&#xff1f; 1.数据结构相关概念 1.什么是数据结构&#xff1f; 数据结构是由“数据”和“结构”两词组合而来。 什么是数据?常见的数值1、2、3、4.、教务系统里保存的用户信息(姓名、性别、年龄、学历等等)、网页里肉眼可以…

TensorBoard进阶

文章目录 TensorBoard进阶1.设置TensorBoard2.图像数据在TensorBoard中可视化3.模型结构在TensorBoard中可视化&#xff08;重点✅&#xff09;4.高维数据在TensorBoard中低维可视化5.利用TensorBoard跟踪模型的训练过程&#xff08;重点✅&#xff09;6.利用TensorBoard给每个…

complex复数库学习

此头文件是数值库的一部分。本篇介绍complex的基本用法。 常用的API如下&#xff1a; 运算 real 返回实部 (函数模板) imag 返回虚部 (函数模板) abs(std::complex) 返回复数的模 (函数模板) arg 返回辐角 (函数模板) norm 返回模(范数)的平方 (函数模板) conj 返回复共轭 (函…

桌面保存的Word文件删除怎么找回?超实用的三个方法?

在日常工作和学习中&#xff0c;我们经常会使用Word文档进行文字编辑和文件保存。但是&#xff0c;有时由于操作失误或系统故障&#xff0c;我们会不小心将存放在电脑桌面重要的Word文件删除了。导致无法挽回的损失&#xff0c;但幸运的是&#xff0c;有一些方法可以帮助我们找…

源代码防泄漏的制胜法宝——沙箱

沙箱技术作为现代信息安全领域的一种重要手段&#xff0c;其在源代码防泄密方面的应用愈发受到业界的关注。源代码作为企业或组织的核心资产&#xff0c;一旦泄露&#xff0c;不仅可能导致知识产权的流失&#xff0c;还可能对企业运营造成重大影响。因此&#xff0c;利用沙箱技…

跨境干货|最新注册Google账号方法分享

谷歌账号对做跨境外贸业务的人来说是刚需&#xff0c;目前来说大部分的海外社媒平台、工具都可以用谷歌账号来注册。但是仍然有很多朋友并不知道如何注册这个谷歌账号&#xff0c;今天就来给大家分享2个注册谷歌账号的方法&#xff0c;一个是手机号注册&#xff0c;一个是如何跳…

面向对象案例:电影院

TOC 思路 代码 结构 具体代码 Movie.java public class Movie {//一共七个private int id;private String name;private double price;private double score;private String director;private String actors;private String info;//get和setpublic int getId() {return id;…

opencv概念以及安装方法

#opencv相关概念介绍 Open Source Computer Vision Library 缩写 opencv 翻译&#xff1a;开源的计算机视觉库 &#xff0c;英特尔公司发起并开发&#xff0c;支持多种编程语言&#xff08;如C、Python、Java等&#xff09;&#xff0c;支持计算机视觉和机器学习等众多算法&a…

如何让自动化测试更加灵活简洁?

简化的架构对于自动化测试和主代码一样重要。冗余和不灵活性可能会导致一些问题&#xff1a;比如 UI 中的任何更改都需要更新多个文件&#xff0c;测试可能在功能上相互重复&#xff0c;并且支持新功能可能会变成一项耗时且有挑战性的工作来适应现有测试。 页面对象模式如何理…

DataWhale-吃瓜教程学习笔记 (七)

学习视频**&#xff1a;第6章-支持向量机_哔哩哔哩_bilibili 西瓜书对应章节&#xff1a; 第六章 支持向量机 - 算法原理 几何角度 对于线性可分数据集&#xff0c;找距离正负样本距离都最远的超平面&#xff0c;解是唯一的&#xff0c;泛化性能较好 - 超平面 - 几何间隔 例…

MSPM0G3507——读取引脚的高低电平方法(数字信号循迹模块)

SYSCFG配置 代码部分 //第一个传感器if( DL_GPIO_readPins(xunji_PORT_PIN1_PORT , xunji_PORT_PIN1_PIN )xunji_PORT_PIN1_PIN) //黑&#xff0c;不亮 高{a1;}if( DL_GPIO_readPins(xunji_PORT_PIN1_PORT , xunji_PORT…

从 Keycloak 导出和导入 Realm 和用户

1. 首先对keycloak 命令有所了解 需要将 Keycloak 中的 Realm 导出或导入时&#xff0c;您可以使用 JSON 文件进行操作。以下是一些有关导出和导入 Realm 的方法&#xff1a; 导出 Realm 到目录&#xff1a; 使用 export 命令将 Realm 导出到目录。在执行此命令时&#xff0c;…

技术分享:直播平台如何开发并接入美颜SDK

本篇文章&#xff0c;笔者将分享直播平台如何开发并接入美颜SDK的技术细节与步骤。 一、选择合适的美颜SDK 首先&#xff0c;选择一款适合的美颜SDK非常重要。市面上有很多优秀的美颜SDK供应商&#xff0c;选择时应考虑以下因素&#xff1a; 功能丰富性&#xff1a;支持美白…

短视频文案提取神器怎么提取抖音视频文案!

很多编导以及视频内容创作者为了提高自己的工作效率还会使用视频转文字提取神器&#xff0c;我们都清楚短视频领域每个平台人群熟悉都有所不同&#xff0c;在分发内容的时候也会调整内容已符合平台属性。 短视频文案提取神器怎么提取抖音视频文案 短视频常见的平台有抖音、西瓜…

linux ifconfig未找到命令

linux ifconfig未找到命令 1、使用yum安装net-tools yum install net-toolsyum报未找到命令请查看文章vim未找到命令&#xff0c;且yum install vim安装vim失败 2、安装后使用ifconfig命令 ifconfig