【算法系列】双指针

news2024/9/25 13:15:56

双指针算法

  • 1. 双指针算法概述
  • 2 经典双指针算法题目分享
    • 1. **==复写零==**
    • 2. ==快乐数(medium)==
    • 3. ==11. 盛最多水的容器==
    • ==4. 有效三⻆形的个数(medium)==
    • ==5. 四数之和==

1. 双指针算法概述

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

2 经典双指针算法题目分享

1. 复写零

1 . 题目链接:1089. 复写零
2 .题目描述:

给你⼀个⻓度固定的整数数组 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]

3 .思路实现

1. 首先利用双指针模拟复写过程来找到我们要复写的最后一个数:

  • 定义一个dest指针为-1,一个cur指针为0,判断arr[cur]是不是0,是0dest走两步,不是0走一步,然后cur++直到dest指针大于或等于数组末尾
    如下图所示:
    在这里插入图片描述 2 .开始复写操作如果arr[cur]不是零arr[dest- -]=arr[cur- -]如果为零arr[dest- -] = 0,arr[dest- -]=0,cur- -,直到cur>=0循环结束
    3 . 注意处理特殊情况:
    如果复写的最后一个数是0会导致dest越界
    在这里插入图片描述
    这种情况我们就把当前0直接进行复写也就是把数组最后一个数字变为0,cur- -,dest-=2;
    4. 代码实现
class Solution 
{
public:
    void duplicateZeros(vector<int>& arr) 
    {
        int dest = -1,cur = 0;
        int size = arr.size();
        //模拟找到倒着复写的第一个
       for(;cur<size;cur++)
       {
        if(arr[cur]==0) dest+=2;
        else dest+=1;
        if(dest>=size-1) break;
       }
       //处理cur指向0导致dest越界
       if(dest>=size)
       {
        arr[size-1] =0;
        dest-=2;
        cur--;
       }
       while(cur>=0)
       {
        if(arr[cur]) arr[dest--] = arr[cur--];
        else 
        {
            arr[dest--] =0;
            arr[dest--] = 0;
            cur--;
        }
       }
    }
};

2. 快乐数(medium)

1 .题目链接:202. 快乐数
2 . 题目描述:

编写⼀个算法来判断⼀个数 n 是不是快乐数。
「快乐数」 定义为:
◦ 对于⼀个正整数,每⼀次将该数替换为它每个位置上的数字的平⽅和。
◦ 然后重复这个过程直到这个数变为 1,也可能是⽆限循环但始终变不到 1 。
◦ 如果这个过程 结果为 1 ,那么这个数就是快乐数。
◦ 如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
⽰例 1:
输⼊: n = 19
输出: true
解释:
19 -> 1 * 1 + 9 * 9 = 82
82 -> 8 * 8 + 2 * 2 = 68
68 -> 6 * 6 + 8 * 8 = 100
100 -> 1 * 1 + 0 * 0 + 0 * 0 = 1
⽰例 2:
输⼊: n = 2
输出: false
解释:(这⾥省去计算过程,只列出转换后的数)
2 -> 4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> 4 -> 16
往后就不必再计算了,因为出现了重复的数字,最后结果肯定不会是 1

3 . 思路实现

根据上述的题⽬分析,我们可以知道,当重复执⾏ x 的时候,数据会陷⼊到⼀个「循环」之中。
⽽「快慢指针」有⼀个特性,就是在⼀个圆圈中,快指针总是会追上慢指针的,也就是说他们总会
相遇在⼀个位置上。如果相遇位置的值是 1 ,那么这个数⼀定是快乐数;如果相遇位置不是 1
的话,那么就不是快乐数。

4 . 代码实现:

class Solution
{
public:
   int sum(int n)
   {
    int ret =0;
    while(n)
    {
        int tem = n%10;
        ret += tem*tem;
        n/=10;
    }
    return ret;
   }
    bool isHappy(int n)
     {
        //由于鸽巢问题最后一定会循环
        int slow = n,fast = sum(n);
        while(slow!=fast)
        {
            slow = sum(slow);
            fast = sum(sum(fast));
        }
        if(slow==1) return true;
        else return false;
    }
};

3. 11. 盛最多水的容器

1 . 题目链接:11. 盛最多水的容器
2 . 题目描述:

给定⼀个⻓度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i,
height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的⽔。
返回容器可以储存的最⼤⽔量。
说明:你不能倾斜容器。
⽰例 1:
输⼊: [1,8,6,2,5,4,8,3,7]
输出: 49
在这里插入图片描述解释:图中垂直线代表输⼊数组 [1,8,6,2,5,4,8,3,7] 。在此情况下,容器能够容纳⽔(表⽰
为蓝⾊部分)的最⼤值为 49 。

4. 思路分析

设两指针 i , j ,分别指向⽔槽板的最左端以及最右端,此时容器的宽度为 j - i 。由于
容器的⾼度由两板中的短板决定,因此可得容积公式 : v = (j - i) * min( height[i], height[j])
便利时我们判断是否height[i]<height[j],i++反之j–;因为我们往里面便利时宽度减小因此此时我们要更新高度。
5. 代码实现:

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

4. 有效三⻆形的个数(medium)

  1. 题目链接:有效三⻆形的个数
  2. 题目描述:

给定⼀个包含⾮负整数的数组 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
解释:
4,2,3
4,2,4
4,3,4
2,3,4

  1. 算法思路:
  • 首先我们把数组排为升序利用最小两边之和大于第三边来进行判断是否为三角形
  • 每次固定一个最大边nums.size()-1(k)处的元素;定义i = 0;j = k-1;
  • 判断nums[i]+nums[j]是否>nums[k]如果是则这个区间都可以构造三角形之后j–
  • 反之i++;
  1. 代码实现:
class Solution 
{
public:
    int triangleNumber(vector<int>& nums) 
    {
        //1.进行排序
        sort(nums.begin(),nums.end());
        int ret = 0;
        //2. 固定最大边
        for(int i = nums.size()-1;i>=2;i--)
        {
             int left = 0;int right = i-1;
            while(left<right)
            {
                if(nums[left]+nums[right]>nums[i])
                {
                    ret+=right-left;
                    right--;
                }
                else left++;
            }
            
        }
        return ret;
    }
};

5. 四数之和

  1. 题目链接:四数之和
  2. 题目描述:

给你⼀个由 n 个整数组成的数组 nums ,和⼀个⽬标值 target 。请你找出并返回满⾜下述全部条件
且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素⼀⼀对应,则认为
两个四元组重复):
◦ 0 <= a, b, c, d < n
◦ a、b、c 和 d 互不相同
◦ nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
⽰例 1:
输⼊:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
比特就业课
⽰例 2:
输⼊:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]
提⽰:
1 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109

  1. 算法思路:

先排序之后固定第一个数在固定第二个数接着用双指针算法去找符合要求的结果就可以了注意这里我们需要处理去重操作就是就是每次我们使用双指针找到一个结果时让左右指针移动到不与此时的元素重合的位置,同时我们固定的第二个数也应该避免重复,最后就是固定的第一个数也应该避免重复这样结果一定不会有重复的

  1. 代码实现:
class Solution 
{
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) 
    {
        sort(nums.begin(),nums.end());
        int n = nums.size();vector<vector<int>> ret;
        //固定一个值
        for(int i = 0;i<n;)
        {
            int tem4 = nums[i];
            //固定第二个值
            for(int j = i+1;j<n;)
            {
                int tem3 = nums[j];
                int left = j+1,right =n-1;
               long long  int target1 = (long long int)target-(long long int)
               nums[i]-(long long int)nums[j];
                while(left<right)
                {
                    if(nums[left]+nums[right]==target1)
                {
                    ret.push_back({nums[i],nums[j],nums[left],nums[right]});
                    int tem1 =nums[left],tem2 = nums[right];
                    while(left<right&&nums[left]==tem1) left++;
                    while(left<right&&nums[right]==tem2) right--;
                }
                else if(nums[left]+nums[right]>target1) right--;
                else left++;
                }
                while(j<n&&nums[j]==tem3) j++;
            }
            while(i<n&&nums[i]==tem4) i++;
        }
        return ret;
    }
};

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

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

相关文章

MMC和eMMC的区别

MMC 和 eMMC 的区别 1. MMC MMC&#xff08;MultiMediaCard&#xff09;是一种接口协议&#xff0c;定义了符合这一接口的内存器&#xff0c;称为 MMC 储存体或 MMC 卡。它是一种非易失性存储器件&#xff0c;广泛应用于消费类电子产品中。 1.1 外观及引脚定义 MMC卡共有七个…

文件解析漏洞合集

IIS 解析漏洞 IIS6 目录解析 打开windows——server2003&#xff0c;在 wwwroot 目录下创建 1.asp &#xff0c;在其中创建的所有文件都会在访问时以 asp 解析出来 畸形文件解析 在wwwroot目录下创建 2.asp;.jpg &#xff0c;此文件上传时是 .jpg 后缀,但解析时由于 iis6 文…

transformer死亡9问

transformer死亡20问 1. Transformer为何使用多头注意力机制&#xff1f;2. Transformer为什么Q和K使用不同的权重矩阵生成&#xff0c;为何不能使用同一个值进行自身的点乘3. Transformer计算attention的时候为何选择点乘而不是加法&#xff1f;两者计算复杂度和效果上有什么区…

C#桌面开发(那些年你总走进误区的技术):异步多线程、异步事务与递归技术

1. 异步多线程 (Asynchronous Multithreading) 在C#桌面开发中&#xff0c;异步多线程是提高应用程序响应速度和性能的关键技术之一。以下是几个深入的技术点和示例代码。 1.1 使用async和await实现异步操作 C#的async和await关键字使得编写异步代码变得更加简单。以下是一个…

老司机也会翻车?通过自动建模技术轻松实现工程机械翻滚保护分析

什么是ROPS分析&#xff1f; ROPS分析&#xff0c;指的是"Roll-Over Protective Structure"&#xff08;翻滚保护结构&#xff09;的简称&#xff0c;这是一种用于评估和设计特殊设备&#xff08;如前装载机、各种挖掘机、履带式推土机&#xff09;的被动安全标准&am…

slam过程中每一帧的gt位姿如何计算

一般得到的每一帧数据类似如下&#xff1a; 4*4的变化矩阵&#xff0c;都属于相机到世界坐标系下的变化矩阵&#xff0c;如果是x,y,z和四元数也可以转换为这种4*4的矩阵。 第一帧为世界坐标系的原点&#xff0c;后续的位姿都基于这个原点进行变化。 def load_poses(path, n_im…

HCIA概述

一、OSI七层模型 1.物理层&#xff08;七层&#xff09; 定义物理设备的标准&#xff0c;主要对物理连接方式&#xff0c;电气特性&#xff0c;机械特性等制定统一标准&#xff0c;传输比特流&#xff0c;因此最小的传输单位——位&#xff08;比特流&#xff09;。 2.数据链…

差分专题的练习

神经&#xff0c;树状数组做多了一开始还想着用树状数组来查询差分数组&#xff0c;但是我们要进行所有元素的查询&#xff0c;直接过一遍就好啦 class Solution { public:int numberOfPoints(vector<vector<int>>& nums) {vector<int> c(105, 0);for (i…

Hadoop的安装和使用-2024年08月01日

Hadoop的安装和使用-2024年08月01日 1.创建Hadoop用户2.SSH登陆权限设置3.java的安装4.Hadoop单机安装配置5.Hadoop伪分布式安装配置 1.创建Hadoop用户 如果安装Ubuntu的时候不是用的“hadoop”用户&#xff0c;那么需要增加一个名为 hadoop的用户首先按ctrlaltt打开终端窗口&…

源代码加密防泄漏如何做?

源代码开发环境复杂&#xff0c;涉及的开发软件、文件类型庞杂多变&#xff0c;究竟有什么源代码加密防泄漏软件能够适应众多开发软件而不影响原有的工作效率&#xff1f; 相信这是很多IT管理员或者老板们都想要了解的问题&#xff0c;今天和行业内专业人士讨论&#xff0c;将…

【docker】虚拟化与docker基础

一、虚拟化 1.虚拟化概述 什么是虚拟化&#xff1f; 虚拟化&#xff1a;将应用程序和系统内核资源进行解耦&#xff0c;以操作系统级别进行隔离&#xff0c;目的是提高资源利用率 2、虚拟化的功能 将虚拟化的性能优化趋近于物理资源的性能&#xff0c;主要用于提高资源利用…

浏览器被360劫持了的解决办法

所有浏览器一打开就是360界面&#xff0c;查询资料解决 以谷歌浏览器为例&#xff1a;打开其exe的位置&#xff0c;将exe文件重命名&#xff0c;再次创建快捷方式即可

Kickstart自动安装系统

目录 一、Kickstart的介绍 1.1 为什么要使用Kickstart? 1.2 如何解决以上问题&#xff1f; 1.3 Kickstart的作用 二、实验环境 2.1 实验所需环境 2.2 测试所给的环境是否可用 三、安装Kickstart配置ks文件 3.1 安Kickstart 3.2 配置ks文件 3.2.1 使用图像配置工具配置…

日志采集格式

本实验需要两个虚拟机&#xff0c;一个用于配置&#xff0c;一个用于查看测试结果 node1主机上的配置 vim /etc/rsyslog.conf #添加配置&#xff0c;写入指定的日志格式 13 module(load"builtin:omfile" Template"HAHA") 14 $template HAHA,"%FROM…

Ceres Cuda加速

文章目录 一、简介二、准备工作三、实现代码四、实现效果参考资料一、简介 字Ceres2.2.1版本之后,作者针对于稠密矩阵的分解计算等操作进行了Cuda加速,因此这里就基于此项改动测试一下效果。 二、准备工作 1、首先是需要安装Cuda这个英伟达第三方库,https://developer.nvidi…

eclipse免安装版64位 2018版本(java开发软件)

前言 eclipse是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言&#xff0c;它只是一个框架和一组服务&#xff0c;用于通过插件组件构建开发环境。 一、下载地址 下载地址&#xff1a;分享文件&#xff1a;eclipse v2018.zip下载 二、安装步骤 1、下载解压后将…

日撸Java三百行(day13:链表)

目录 一、链表的基础知识 二、链表的代码实现 1.链表创建 2.链表遍历 3.链表定位查找 4.链表插入 5.链表删除 6.数据测试 7.完整的程序代码 总结 一、链表的基础知识 在之前顺序表的学习中&#xff0c;我们其实提到过链表。链表它是线性表在不同的物理存储方式下派生…

HarmonyOS 音视频之音频采集实战

HarmonyOS 音视频之音频采集实战 背景 应用开发过程中很多场景都有音频采集需求&#xff0c;比如聊天功能的发送语音功能&#xff0c;实时语音转文本功能&#xff0c;实时语音通话&#xff0c;实时视频通话等。在Android和iOS端&#xff0c;系统提供了两种形式&#xff1a; …

图+代码 | Bloom Filter实现及应用

什么是布隆过滤器&#xff08;Bloom Filter&#xff09;&#xff1f; 布隆过滤器是一种空间复杂度很低的概率型数据结构&#xff0c;用于判断一个元素是否在一个集合中。它有两种可能的返回结果&#xff1a; 元素可能在集合中&#xff1a;这可能是一个真阳性&#xff08;确实…

使用Variadic Templates(可变参数模板)实现printf

最近学习了C2.0版本的一些新的特性&#xff0c;利用Variadic Templates&#xff08;可变参数模板&#xff09;实现printf函数。 语言环境 Dev-C 5.11 并需要自己的环境是支持C11的&#xff0c;例如:Dev-C 5.11可以通过以下步骤进行修改&#xff1a; 源码 #include <io…