双指针算法

文章目录

  • 双指针算法
  • leetcode题目


双指针算法

双指针算法可以实现对于时间复杂度降一维度,使得O(n2)的算法时间复杂度变为O(n)

指针类型

  1. 对撞指针
  2. 快慢指针

对撞指针

  • 一般是用于顺序结构中的,也可以称为左右指针,从两端向中间移动,最左、最右,向中间逐渐逼近。
  • 对撞指针的结束条件一般为left==right 或者 left>right

快慢指针

  • 基本思想为使用两个移动速度不同的指针在数组或者链表等序列结构上移动,比如在处理环形链表或者是数组时很有用
  • 只要是我们研究的问题涉及到循环往复的情况,就可以考虑使用快慢指针的思想
  • 快慢指针的实现方式有很多种,但是最为经典的是,在一次循环中,每一次让慢的指针移动一步,快的指针移动两步,如果成环(循环),那么两个指针会相遇

leetcode题目

题目链接:移动零
在这里插入图片描述

class Solution {
public:
    void moveZeroes(vector<int>& nums) {    
        //这是数组划分的题目,我们使用双指针的方式来解决
        //cur=0 dest=-1 dest指向的是最后一个不为0的数
        //移动cur,查找是否有nums[cur]!=0 那么 与nums[++dest] 交换,使得
        //[0,dest]  [dest+1,cur-1]  [cur,n-1]
        //数组分为上述三部分,第一部分为非零部分   第二部分为0部分,第三部分为未处理的部分
        //我们将非零部分,找到之后就放在当前非零数组的最后一个元素之后的位置,这样就可以实现分块
        for(int cur=0,dest=-1;cur<nums.size();cur++)
        {
            if(nums[cur])
            {
                //如果不为0
                swap(nums[++dest],nums[cur]);
            }
        }
    }
};

为什么是swap(nums[++dest],nums[cur]),这是因为我们规定的是dest位置是已处理区域的最后一个非零元素,我们发现在未处理区域cur之后,发现非零元素,将++dest,得到最后一个元素的后一个位置,进行交换,自然实现了0(已处理的零区域)与nums[cur]的移动

题目描述:复写零

在这里插入图片描述

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        //对于数组的元素进行处理,我们使用双指针
        //因为复写,遇到0要复写0,所以从前向后的双指针不行,我们使用从后向前指针,这样就不会造成数据被覆盖
        //从后向前进行双指针,我们首先要确定的是开始判断是否复写的起始位置
        //起始位置的确定,就是复写完毕之后的数组最后一个元素在原先数组中的下标位置

        //我们使用双指针进行判断,找到确定的位置
        
        //先找到最后一个位置
        
        //找到位置之后,可能会有种可能nums[dest]=0 所以我们将这种可能避免
        int cur=0,dest=-1;   //cur比dest多1,实际上就是先++cur,然后进行判断
        while(cur<arr.size())
        {
            if(arr[cur])
            {
                dest++;
            }
            else{
                dest+=2;
            }
            if(dest>=arr.size()-1)
            {
                break;
            }
            cur++;
        }
        cout<<arr[cur]<<endl;
        
        //处理边界问题,dest可能大于arr.size()-1
        if(dest==arr.size())
        {
            arr[arr.size()-1] =0;
            dest-=2;
            cur--;
        }

        //开始复写 ,从后向前
        while(cur>=0)
        {
            if(arr[cur])
            {
                //如果不为0
                arr[dest]=arr[cur];
                cur--;
                dest--;
            }
            else
            {
                //为0 复写
                arr[dest]=arr[cur];
                arr[--dest]=arr[cur];
                --dest;
                --cur;
            }
        }
    }
};

题目描述:快乐数

在这里插入图片描述

class Solution {
public:
    //得到每一位数字的平方和
    int func(int n)
    {
        int ans=0;
        while(n)
        {
            ans+=(n%10)*(n%10);
            n=n/10;
        }
        return ans;
    }
    bool isHappy(int n) {
        //根据题意所知,不管如何都会形成一个循环
        //根据循环,我们知道之前判断循环链表的做法,快慢指针的形式

        //slow和fast都是指向经过平方之后的数字,来代替指针 
        //slow走一步平方一次,fast平方两次
        //实现平方的函数
        cout<<func(100)<<endl;//检验func函数
        int slow=n;
        int fast=n;
        while(1)
        {
            //直到相等才停止
            slow=func(slow);
            fast=func(fast);
            fast=func(fast);
            if(slow==fast)
            {
                break;
            }
        }
        if(slow==1)
        {
            return true;
        }else
        {
            return false;
        }
        //return true;
    }
};

题目描述:盛最多水的容器

在这里插入图片描述

class Solution {
public:
    int maxArea(vector<int>& height) {
        //使用双指针的算法来解决
        //在两边设置指针,移动较小的哪一方指针,然后计算此时的体积,不断的移动,直到相遇

        int left=0,right=height.size()-1,ans=0;
        while(left<right)
        {
            //先得到此时的体积
            int v=(right-left)*min(height[left],height[right]);
            ans=max(v,ans);
            if(height[right]>height[left])
            {
                left++;
            }
            else
            {
                right--;
            }
        }
        return ans;
   }
}

题目描述:有效三角形的个数

在这里插入图片描述

class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int ans=0;
        for(int i=nums.size()-1;i;i--)
        {
            int target=nums[i];
            int left=0,right=i-1;
            while(left<right)
            {
                if(nums[left]+nums[right]>target)
                {
                    //满足三角形
                    ans+=right-left;
                    right--;
                    //left++;
                }
                else
                {
                    left++;
                }
            }
        }
        return ans;
    }
};

利用数组元素的单调性,先确定一个元素,然后使用双指针,判断当前三者是否符合三角形,如果符合,根据单调性,left左边的所有都符合,所以ans+=right-left,然后向左移动right,如果不符合,那么向右移动left,一直判断,一直ans+=right-left 直到left<right 更换下一位c,最后循环操作,返回ans

题目描述:和为s的两个数字

在这里插入图片描述

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        //因为是 递增的数组   
        //我们利用双指针算法来解决该问题   利用单调性进行优化
        vector<int> v;
        int left=0,right=nums.size()-1;
        while(left<right)
        {
            if(nums[left]+nums[right]<target)
            {
                left++;  //说明当前最大值加上最小值还是小于target
            }
            else if(nums[left]+nums[right]== target)
            {
                v.push_back(nums[left]);
                v.push_back(nums[right]);
                return v;
            }
            else
            {
                right--;
            }
        }
        return v;
    }
};

题目概述:三数之和

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        //进行排序,然使用双指针算法,先确定一个数字,然后移动另外两个指针进行加减
        vector<vector<int>> vv;
        for(int i=0;i<nums.size();)
        {
            if(nums[i]>0) break;
            int left=i+1,right=nums.size()-1;
            while(left<right)
            {
                int sum=nums[left]+nums[right];
                int target=-nums[i];
                if(sum==target)
                {
                    vector<int> v;
                    v.push_back(nums[i]);
                    v.push_back(nums[left]);
                    v.push_back(nums[right]);
                    //找到一次之后,对于相邻重复的元素进行跨越
                    vv.push_back(v);
                    //去重操作 left 和 right
                    left++,right--;
                    while(left<right && nums[left] == nums[left-1]) left++;
                    while(left<right && nums[right] == nums[right+1]) right--;
                    //防止越界
                }else if(sum>target)
                {
                    right--;
                }else 
                {
                    left++;
                }
            }
            //去重操作 i
            i++;
            while(i<nums.size() && nums[i] == nums[i-1]) i++;
        }
        return vv;
    }
};

题目描述:四数之和

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        //先固定一个数a,然后剩余三个数字用三数之和 的内容来解决
        sort(nums.begin(),nums.end());
        vector<vector<int>> vv;
        for(int i=0;i<nums.size();)
        {
            int a=nums[i];
            for(int j=i+1;j<nums.size();)
            {
                //三数之和的内容
                int num=target-a;
                int left=j+1,right=nums.size()-1;
                while(left<right)
                {
                    int sum=nums[left]+nums[right];
                    long t=(long)num-nums[j];
                    if(sum>t)
                    {
                        right--;
                    }
                    else if(sum<t)
                    {
                        left++;
                    } 
                    else
                    {
                        vv.push_back({nums[i],nums[j],nums[left],nums[right]});
                        //加入vector后,处理重复问题 left 和 right
                        left++, right--;
                        while(left<right && nums[left] ==  nums[left-1]) left++;
                        while(left<right && nums[right] ==  nums[right+1]) right--;
                    }
                }
                //去重处理 j
                j++;
                while(j<nums.size() && nums[j] == nums[j-1]) j++;
            }
            i++;
            while(i<nums.size() && nums[i] == nums[i-1]) i++; 
        }
        return vv;
    }
};

总结:
双指针的使用场景有很多种,使用对撞指针还是快慢指针是根据题意分析的,如果成环我们就使用快慢指针,双指针的算法是根据暴力算法的优化得到的,通过省去不必要的迭代,来实现优化。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

超导热催生meme,换汤不换药的投机轮回

文/章鱼哥 出品/陀螺财经 币圈对炒作meme概念的热情从未消亡过。 随着一种名为LK-99的物质被发现&#xff0c;围绕超导的兴奋不仅激发了科学界&#xff0c;加密货币相关概念也与之沸腾。不出所料&#xff0c;与此前围绕元宇宙、AI大肆炒作一样&#xff0c;许多meme代币已经出现…

Maven基础总结

前言 Maven 是一个项目管理工具&#xff0c;可以对 Java 项目进行构建、依赖管理。 基本要求掌握 配置Maven环境直接查。 得会在IDEA创建Maven的java项目吧、会创建Maven的web项目吧、会创建多模块项目吧。 得会配置插件pligin、依赖dependency吧 一、Maven四大特性 1、…

github版面混乱加载不出的解决办法

最近出现打开github 界面加载不成功&#xff0c;网页访问乱码&#xff0c;打开chrome的检查发现 github的github.githubassets.com 拒绝访问&#xff0c; 解法&#xff1a; 1.先打开hosts文件所在的目录C:\Windows\System32\drivers\etc 2.右键点击hosts文件-选择用记事本或者…

使用阿里云服务器部署和使用GitLab

本文阿里云百科分享使用阿里云服务器部署和使用GitLab&#xff0c;GitLab是Ruby开发的自托管的Git项目仓库&#xff0c;可通过Web界面访问公开的或者私人的项目。本教程介绍如何部署和使用GitLab。 目录 准备工作 部署GitLab环境 使用GitLab 登录GitLab 生成密钥对文件并…

EVE-NG 隐藏没有镜像的模板

eve-ng 默认情况下&#xff0c;在添加node时&#xff0c;会列出所有的模板&#xff0c;这样用着很不方便。 通过以下方式&#xff0c;可以使没有设备的模板不可见 cp /opt/unetlab/html/includes/config.php.distribution /opt/unetlab/html/includes/config.php 打开 config…

Prometheus流程图(自绘)-核心组件-流程详解

阿丹手绘流程图&#xff1a;图片可能有点小查看的时候放大看看哈&#xff01; prometheus核心组件 prometheus server Prometheus Server是Prometheus组件中的核心部分&#xff0c;负责实现对监控数据的获取&#xff0c;存储以及查询。Prometheus Server可以通过静态配置管理…

[excel]vlookup函数对相同的ip进行关联

一、需求&#xff08;由于ip不可泄漏所以简化如下&#xff09; 有两个sheet: 找到sheet1在sheet2中存在的ip&#xff0c;也就是找到有漏洞的ip 二、实现 vlookup函数有4个参数 第一个:当前表要匹配的列&#xff0c;选择第一个sheet当前行需要处理的ip即可 第二个:第二个shee…

东南大学齿轮箱故障诊断(Python代码,MSCNN结合LSTM结合注意力机制模型,代码有注释)

运行代码要求&#xff1a; 代码运行环境要求&#xff1a;Keras版本>2.4.0&#xff0c;python版本>3.6.0 1.东南大学采集数据平台&#xff1a; 数据 该数据集包含2个子数据集&#xff0c;包括轴承数据和齿轮数据&#xff0c;这两个子数据集都是在传动系动力学模拟器&am…

分布式系统监控zabbix安装部署及使用

目录 一.zabbix监控 1.什么是zabbix 2.zabbix功能 3.zabbix的构成 4.zabbix的3种架构 4.1 C/S架构 4.2 分布式架构&#xff1a;zabbix-proxy-client架构 4.3 master-node-client架构 6.zabbix监控模式 二.zabbix部署及图形化页面显示设置(192.168.158.25) 1.zabbix安装…

JIRA:项目管理的秘密武器

引言 在当今动态且快速变化的商业环境中&#xff0c;项目管理已经成为任何组织成功的关键因素。能够有效地管理项目&#xff0c;保证项目在设定的时间和预算内按照预期的质量完成&#xff0c;是每个项目经理的目标。为了实现这个目标&#xff0c;项目经理需要依赖强大的工具&a…

思科交换机和路由器使用TFTP备份和还原配置文件

&#xff08;1&#xff09;给交换机配置管理地址&#xff0c;保证交换机与服务器相连通 SW1(config)#int vlan 1 SW1(config-if)#ip add 192.168.1.1 255.255.255.0 SW1(config-if)#no shut SW1#write &#xff08;2&#xff09;备份startup-config到服务器 SW1#copy startup…

React 入门学习

React 入门 一、基本认识1.1、前言1.2、什么是1.3、编译<br>1.4、特点1.5、高效 二、React环境和基本使用2.1、环境搭建2.2、脚手架项目基本使用2.2.1、src2.2.2、public2.2.3、package.json 三、JSX的理解和使用四、模块与模块化, 组件与组件化的理解4.1、模块与组件4.2…

chrome V3 插件开发 基础

目录 准备popup通信popup 发消息给 backgroundpopup 发消息给 content长期连接 如何页面上添加一个按钮&#xff1f;tabs.onUpdatedcontent-script.jsinject.js 右键菜单chrome.contextMenus举个例子添加关于报错&#xff08;cannot create item with duplicate id XXX&#xf…

鉴源实验室丨汽车网络安全攻击实例解析(二)

作者 | 田铮 上海控安可信软件创新研究院项目经理 来源 | 鉴源实验室 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 引言&#xff1a;汽车信息安全事件频发使得汽车行业安全态势愈发紧张。这些汽车网络安全攻击事件&#xff0c;轻则给企业产品发布及产品…

spring-自定义AOP面向切面注解--统一切面处理-登陆信息采集

2023华为OD统一考试&#xff08;AB卷&#xff09;题库清单-带答案&#xff08;持续更新&#xff09;or2023年华为OD真题机考题库大全-带答案&#xff08;持续更新&#xff09; 1. 先写一个登陆记录注解&#xff08;//记录&#xff1a;XXX时间&#xff0c;XXX姓名&#xff0c;XX…

【人工智能前沿弄潮】——生成式AI系列:Diffusers应用 (1) 了解Pipeline 、模型和scheduler

Diffusers旨在成为一个用户友好且灵活的工具箱&#xff0c;用于构建针对您的用例量身定制的扩散系统。工具箱的核心是模型和scheduler。虽然DiffusionPipeline为了方便起见将这些组件捆绑在一起&#xff0c;但您也可以拆分管道并单独使用模型和scheduler来创建新的扩散系统。 …

使用AI工具Lama Cleaner一键去除水印、人物、背景等图片里的内容

使用AI工具Lama Cleaner一键去除水印、人物、背景等图片里的内容 前言前提条件相关介绍Lama Cleaner环境要求安装Lama Cleaner启动Lama CleanerCPU方式启动GPU方式启动 使用Lama Cleaner测试结果NO.1 检测框NO.2 水印NO.3 广州塔NO.4 人物背景 参考 前言 由于本人水平有限&…

Faker库详解 - Python中的随机数据生成器

文章目录 Faker介绍Faker安装Faker使用基本使用方法随机生成人物相关的基础信息随机生成地理相关的信息随机生成网络相关的信息随机生成日期相关的信息随机生成数字/字符串/文本随机生成列表/元组/字典/集合/迭代器/json随机生成文件相关的信息随机生成颜色/表情每次请求获取相…

2023“钉耙编程”中国大学生算法设计超级联赛(5)

Typhoon 计算几何&#xff0c;点到线段距离 String Magic (Easy Version) Manacher可持久化线段树 Touhou Red Red Blue DP 模拟 Expectation (Easy Version) 签到&#xff0c;组合数学 Tree 树形DP Cactus Circuit 仙人掌图&#xff0c;tarjan找简单环 Counting Stars 暴力…

Mac安装nvm教程及使用

nvm 是 node 版本管理器&#xff0c;也就是说一个 nvm 可以管理多个 node 版本&#xff08;包含 npm 与 npx&#xff09;&#xff0c;可以方便快捷的安装、切换 不同版本的 node。 1、直接通过brew安装 执行命令&#xff1a;brew install nvm PS&#xff1a; 如果没有安装br…