双指针算法(一)

news2024/9/21 12:36:05

目录

移动零

复写零

快乐数

盛水最多的容器

双指针与单调性结合

有效三角形的个数

查找总价格为目标值的两个商品

两数之和 Ⅱ - 输入有序数组 


双指针算法是通过定义两个指针不断单向移动来解决问题的一种算法。但双指针算法,是一个抽象的思想概念,可以用来解决数组划分、数组分块等问题。

它通常并不是真的定义两个指针,例如在 vector、string 中就经常通过下标来充当指针。

移动零

力扣链接:移动零

题目:给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

题目的意思:很明确,将所有非零元素移至数组最前面,数组中的零都放在数组偏后面的位置。

思路:定义两个 ‘指针’ cur 和 dest ,cur指针用来从左往右扫描遍历数组,一直指向扫描过的最后一个元素,dest指针一直指向遍历过的数组范围内最后一个不为零的位置。

具体做法:定义cur为0,dest为 -1(因为不知道第一个位置是否需要被交换),cur指针从左往右扫描数组,遇到等于0的元素直接跳过,遇到不等于零的元素,先让 dest 指针的位置加1,然后交换 cur 和 dest 两个位置的值后,两个指针再分别后移一位......如此循环直到最后cur扫描至数组最后一位。

此时数组就被划分为两个部分,因为dest指向的是遍历过的数组范围内最后一个不为零的位置,而扫描已经结束,所以 dest 指针指向的是最后一个不为 0 的位置,cur指针指向的是数组最后一个位置,两个指针中间的数就全是移动后的零。

代码详解(核心代码模式)

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int cur=0,dest=-1;
        while(cur<nums.size())
        {
            if(nums[cur]==0)
                cur++;
            else
            {
                dest++;
                swap(nums[dest],nums[cur]);
                cur++;
            }
        }
    }
};

复写零

力扣链接:复写零

题目:给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。

注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。

思路:先根据 ‘异地’ 操作将数组进行按规则复写,然后优化为双指针下的 ‘就地’ 操作。

异地操作方法:两个指针 cur 和 dest 分别指向两个数组,一个原数组,一个与原数组空间相同的新数组。利用 cur 指针对原数组进行遍历,遇到非零元素,在新数组中按序拷贝,遇见0元素,就在新数组中连续拷贝两次。 

原地操作优化思路:先使用 ‘异地’ 操作的思想,找到最终两个指针复写结果的位置,从前往后完成复写!

具体做法:

(1)定义 cur 为0,dest 为 -1。cur 指针遍历数组,遇到不为0的数,dest向前移动一位,遇到0,dest 向前移动两位,当 dest 到达数组最后一个位置的时候,cur和dest的位置就是从后往前开始复写的位置。

(2)cur 指针开始向前走,遇到非零,dest就将这个数拷贝过去,dest前移一位;遇到0,dest就拷贝两个零,同时向前移动两位.....当cur移动到数组最开始的位置的时候,复写就结束了!

代码详解(核心代码模式)

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int cur = 0, dest = -1;
        int n = arr.size();
        //第一步:找到复写的位置
        while (dest <n)
        {
            if (arr[cur] != 0)
                dest++;
            else if (arr[cur] == 0)
                dest += 2;
            if (dest >=n - 1)
                break;
            cur++;
        }
        //处理特殊情况
        if (dest==n)//dest指针越界,说明原数组倒数第二个位置为0
        {
            cur--;
            arr[n - 1] = 0;
            dest -= 2;
        }
        while (cur >= 0)
        {
            if (arr[cur] != 0)
            {
                arr[dest--] = arr[cur];
            }
            else if (arr[cur] == 0)
            {
                arr[dest--] = arr[cur];
                arr[dest--] = arr[cur];
            }
            cur--;
        }
    }
};

注意点:当原数组的倒数第二个位置为0的时候,需要在循环结束后单独处理一下,否则就会造成数组越界! 

快乐数

力扣链接:快乐数

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

思路:快乐数定义的第二点非常重要,‘重复这个过程直到这个数字变为 1 ,也可能是 无限循环 但始终变不到1’。那么这个问题中,运算每进行一步,都可以看做链表往前走一步,其实可以抽象成链表成环问题,再使用 ‘快慢指针’ 来解决。

这里的快指针就是计算每位平方和后再将结果计算平方和,慢指针就只计算一次平方和......一直进行这样的操作,既然这个数字最后都会‘循环’,那么就是变成1循环还是其他多个数进行循环的问题了。

当快指针和慢指针相遇(相等)的时候,判断这个数是不是1,如果是1,这个数 n 就是快乐数,反之则不是。

代码详解(核心代码模式)

class Solution {
public:
    int Sumbit(int n)
    {
        int sum = 0;
        while(n)
        {
            int x = n % 10;
            sum += x*x;
            n /= 10;
        }
        return sum;
    }
    bool isHappy(int n) {
        //快慢指针
        int fast = n,slow = n;
        do
        {
            slow = Sumbit(slow);
            fast = Sumbit(Sumbit(fast));    
        }while(fast != slow);
        if(fast == 1)
            return true;
        else
            return false;
    }
};

快指针和慢指针刚开始都等于这个数字 n,定义一个计算各位平方和的函数:慢指针调用1次,快指针调两次。然后使用 do...while 循环找到下次 快慢指针相等的值,判断这个值是否等于1即可。

盛水最多的容器

力扣链接:盛水最多的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

思路:容器能盛水的最大高度是由两侧最低的柱子决定的!先计算出两侧开始的水的容量,设置为Max。利用双指针从两边到中间,高度较低一边的指针向中间移动,并重新计算容量,如果新容量大于初始的Max,就更新Max的值。两个指针相遇的时候,Max的值就是容器能容纳水的最大值。

代码详解(核心代码模式)

class Solution {
public:
    int V(vector<int>& height , int x , int y)
    {
        return min(height[x],height[y]) * (y-x);
    }
    int maxArea(vector<int>& height) {
        int left = 0, right = height.size()-1;
        int Max = 0;
        while(left != right)
        {
            int v = V(height,left,right);
            Max = max(v,Max);
            if(height[left] < height[right])
            {
                left++;
            }   
            else
                right--;
        }
        return Max;
    }
};

双指针与单调性结合

有效三角形的个数

力扣链接:有效三角形的个数

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。

前提:一组数中,两个较小的数相加大于较大的数,就能组成三角形(任意三边之和大于第三边的一组数能构成三角形的推论)

思路:先排序,保证不降序排列。从数组右侧开始固定最大的数,利用双指针(一个指针在最左边,另一个指针在固定数的左边),来确定固定的这个数的左半区间中能构成三角形的个数,然后向左更新这个被固定的数,重复上面的步骤,直至左半区间只有两个数为止循环结束。

确定左半区间中能构成三角形的个数:设固定的数位置为 tmp,则right的位置为 tmp -1 ,left 位置的值为 0。判断两个位置数相加后的结果与固定数的大小如果大于,说明两个指针 [ left 、right ) 之间的所有数,都能与 right、tmp形成三角形,则能形成三角形的个数将会增加 ( right - left )个如果小于等于,说明 left 这边的值不够大,将 left 指针再加1,重复上面的比较过程。当left指针和right指针相遇,或者两者的数大于 tmp 位置的数时结束本轮循环,更新固定数的位置继续上述过程。

代码详解(核心代码模式)

class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        //只要两个小数相加大于大数,就能构成三角形
        sort(nums.begin(),nums.end());//先排序
        size_t sum = 0;
        //外层循环,固定一个最大的数
        for(int tmp = nums.size()-1; tmp >= 2; tmp --)
        {
            int right = tmp-1;
            int left = 0;
            //利用双指针算法
            while(right != left)
            {
                if(nums[left] + nums[right] > nums[tmp])
                {
                    sum += (right-left);
                    right--;
                }
                else
                {
                    left++;
                }
            }
        }
        return sum;
    }
};

查找总价格为目标值的两个商品

两数之和 Ⅱ - 输入有序数组 

这两个题是一种思路,一个返回数。一个返回下边。但都是双指针思路、利用单调性来做题!

设定两个指针,一个在左边,一个在右边,因为数组是有序的,所以左边是最小的,右边是最大的,两个指针往中间移动,根据和与目标数值的大小关系,来确定指针的移动,最后两个指针停留于的位置,就是两个数的和等于目标值的位置。 

查找总价格为目标值的两个商品代码详解(核心代码模式)

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

两数之和 Ⅱ - 输入有序数组(核心代码模式) 

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

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

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

相关文章

京微齐力:基于H7的平衡控制系统(一、姿态解析)

目录 前言一、关于平衡控制系统二、实验效果三、硬件选择1、H7P20N0L176-M2H12、MPU6050 四、理论简述五、程序设计1、Cordic算法2、MPU6050采集数据3、fir&iir滤波4、姿态解算 六、资源消耗&工程获取七、总结 前言 很久之前&#xff0c;就想用纯FPGA做一套控制系统。可…

橘子学K8S01之容器中所谓的隔离

我们一直都在说容器就是一个沙盒&#xff0c;沙盒技术顾名思义就是像一个集装箱一样&#xff0c;把应用(服务&#xff0c;进程之类的)装起来的技术&#xff0c;这样每个进程在自己的沙盒中和其他的沙盒隔离开来&#xff0c;每个沙盒之间存在一个边界使得他们互不干扰&#xff0…

C# 字符串格式化

写在前面 在日常编程中&#xff0c;经常需要对字符串进行格式化操作&#xff0c;以便呈现为不同的格式&#xff0c;满足各种各样的显示需求&#xff0c;C#的字符串格式化参数是非常丰富的&#xff0c;这里做个简单的列举&#xff0c;以供后续参考和延伸。 代码实现 var curr…

Pr自动从视频脚本剪辑视频FirstCut插件免费下载

FirstCut 插件将自动从视频脚本中剪辑视频&#xff0c;在例如新闻、采访、自媒体视频等带有配音或字幕内容的视频制作中提高了粗剪效率。 使用 FirstCut&#xff0c;大大缩短了粗剪的时间&#xff0c;而不是转到每个视频文件并找到 IN 点和 OUT 点&#xff0c;然后将其插入到序…

yolov8常用命令

1.运行预测 &#xff08;1&#xff09;运行目标检测模型&#xff1a; yolo predict modelyolov8n.pt sourcebus.jpg &#xff08;2&#xff09;运行目标检测与分割模型 yolo predict modelyolov8n-seg.pt sourcebus.jpg 2.模型训练 复制coco128.yaml更名为myDetect.y…

c题目17:写一个swap函数,可以交换2个整数变量的值。(分别用普通方式和指针方式实现,对比结果)

每日小语 我坐着&#xff0c;观望世界上所有的忧患&#xff0c;所有的压迫和耻辱看着&#xff0c;听着&#xff0c;一声不响。——惠特曼 自己思考 最近这段时间新的感悟似乎也没有&#xff0c;但我发现我和别人的思想越来越不同&#xff0c;只能跟极少数人产生共鸣&#xff0…

JVM-接口响应时间很长解决办法

问题 在程序运行过程中&#xff0c;发现有几个接口的响应时间特别长&#xff0c;需要快速定位到是哪一个方法的代码执行过程中出现了性能问题。 解决思路 已经确定是某个接口性能出现了问题&#xff0c;但是由于方法嵌套比较深&#xff0c;需要借助于算法定位到具体的方法。 A…

为什么要有arp以及arp原理

今天给大家说说arp吧&#xff01;在学网络的时候&#xff0c;我们知道的是自顶向下交付数据包。但是我们在交付给数据链路层的时候&#xff0c;我们已经有了ip的报头&#xff0c;但是要注意的是&#xff0c;ip层可不会给我们传输数据包&#xff0c;他还要向下交付。我们学过ip协…

一分钟带你了解电容

电容器中的电容究竟是怎么定义的&#xff1f; 一个电容器&#xff0c;如果带1库的电量时两级间的电势差是1伏&#xff0c;这个电容器的电容就是1法拉&#xff0c;即&#xff1a;CQ/U 。但电容的大小不是由Q&#xff08;带电量&#xff09;或U&#xff08;电压&#xff09;决定…

Ubuntu18.04.6下samba服务的安装及配置

目录 01 安装samba服务&#xff1a; 03 重启samba服务 04 设置samba登录密码 05 测试 前言 虚拟机下Ubuntu18.04.6samba服务的安装及配置 01 安装samba服务&#xff1a; 命令行中输入 sudo apt-get install samba 02 配置 2.1 先创建一个需要共享的目录&#xff0c…

探索 Coinbase 二层链 Base 的潜力与风险

作者&#xff1a;lesleyfootprint.network 在不断变化的加密货币领域&#xff0c;Coinbase 已经确立了自己领先中心化交易所&#xff08;CEX&#xff09;的地位。然而&#xff0c;Coinbase 坚信去中心化是创造一个开放、全球范围内对每个人都可访问的加密经济的关键&#xff0…

【Axure教程】区间评分条

区间评分条是一种图形化的表示工具&#xff0c;用于展示某一范围内的数值或分数&#xff0c;并将其划分成不同的区间。这种评分条通常用于直观地显示数据的分布或某个指标的表现。常用于产品评价、调查和反馈、学术评价、健康评估、绩效评估、满意度调查等场景。 所以今天作者…

【Python】—— 文本分析

文本分析 相关知识1. 文本数据处理2. 文本可视化3. Python编程4. 词频统计5. 人名提取6. 自然段划分7. 人物出现频率分布分析8. 词云生成 实验内容数据下载地址&#xff1a;1.对纯英文小说进行分析。2.对中文小说进行分析。 问题与解决附录1.对纯英文小说进行分析。2.对中文小说…

【C语言】超详解strncpystrncatstrncmpstrerrorperror的使⽤和模拟实现

&#x1f308;write in front :&#x1f50d;个人主页 &#xff1a; 啊森要自信的主页 ✏️真正相信奇迹的家伙&#xff0c;本身和奇迹一样了不起啊&#xff01; 欢迎大家关注&#x1f50d;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;>希望看完我的文章对你有小小的帮助&am…

Python自动化测试系列[v1.0.0][多种数据驱动实现附源码]

前情提要 请确保已经熟练掌握元素定位的常用方法及基本支持&#xff0c;请参考Python自动化测试系列[v1.0.0][元素定位] 数据驱动测试是自动化测试中一种重要的设计模式&#xff0c;这种设计模式可以将测试数据和测试代码分开&#xff0c;实现数据与代码解耦&#xff0c;与此同…

openHarmony添加system_basic权限安装报错

openHarmony添加system_basic权限安装报错 12/14 13:49:57: Install Failed: [Info]App install path:D:\huawei\project\FCTTest\entry\build\default\outputs\default\entry-default-signed.hap, queuesize:0, msg:error: failed to install bundle. error: install failed …

k8s常用命令及示例(三):apply 、edit、delete

k8s常用命令及示例(三)&#xff1a;apply 、edit、delete 1. kubectl apply -f 命令&#xff1a;从yaml文件中创建资源对象。 -f 参数为强制执行。kubectl apply和kubectl create的区别如下&#xff1a;kubectl create 和 kubectl apply 是 Kubernetes 中两个常用的命令&…

若依打包将vue放到.jar里面部署

1.vue静态文件&#xff0c;以及单页面 ruoyi-admin\src\main\resources\static \ruoyi-admin\src\main\resources\templates 2.后台开放白名单 "/cms", "/cms#/login" 3. mvc访问vue页面入口&#xff0c;接口 package com.ruoyi.web.controller.syst…

信号继电器 DX-31B DC220V 电压型 带板前接线底座

系列型号 DX-31B信号继电器DX-31BJ信号继电器 DX-32A信号继电器DX-32AJ信号继电器 DX-32B信号继电器DX-32BJ信号继电器 DX-31A信号继电器DX-33/1信号继电器 DX-33/2信号继电器DX-33/3信号继电器 DX-33/4信号继电器DX-33/5信号继电器 一. 继电器用途 DX-30系列信号继电器…

从池化的角度看GNN(包含PR-GNN,EdgePool等7篇论文)下篇

从池化的角度看GNN&#xff08;包含PR-GNN&#xff0c;EdgePool等7篇论文&#xff09;下篇 前言一些总结一些早期论文的简要介绍5️⃣论文StructPool&#xff1a;《StructPool: Structured Graph Pooling via Conditional Random Fields》6️⃣论文ASAP&#xff1a;《ASAP: Ada…