刷刷刷——双指针算法

news2024/12/25 23:48:02

在这里插入图片描述

双指针算法

这里的双指针,可能并不是真正意义上的指针,而是模拟指针移动的过程。

常见的有两种:

双指针对撞:

  • 即在顺序结构中,指针从两端向中间移动,然后逐渐逼近

  • 终止条件一般是:

    left == right 指向同一个位置

    or left>right指针错开

快慢指针:

  • 该方法一般用于处理环形链表或者是数组

283. 移动零

算法原理

这里有两种方法:

  • 方法1: 开辟一个新的空间,如果不是0,而增添到新的空间,最后在补齐0即可

  • 方法2:采用前后指针,cur遍历数组,prev指向最后一个非0元素(我们采用该解法)

    image-20230912225033669

代码实现

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

1089. 复写零

算法原理

2种方法:

  • 方法1:开辟一个容量与参数一样的新的空间,遇到0就写2次,直到空间与满为止

  • 方法2:找到最后一个复写的数(判断cur的值,决定dest是走一步还是走两步)然后再从后往前遍历(从前往后遍历会导致后面的数被修改),完成复写操作

    这里要注意处理边界情况

    image-20230912230553216

代码实现

“异地操作”

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        vector<int> tmp;
        tmp.resize(arr.size());
        int cur = 0;
        int prev = 0;
        while(cur<arr.size())
        {
            if(prev<arr.size() && arr[cur] == 0)
            {
                tmp[prev++] = arr[cur];
            }
            if(prev<arr.size())
            {
                tmp[prev++] = arr[cur];
            }
            else
                break;
            ++cur;
        }
        arr = tmp;
    }
};

“本地操作”

class Solution
{
public:
void duplicateZeros(vector<int>& arr) 
{
    int cur = 0;
    int dest = -1;
    //找最后一个复写的数
    while (cur < arr.size())
    {
        if (arr[cur] == 0)
        {
         dest += 2;
        }
        else
        {
         dest++;
        }

        if(dest >= arr.size() - 1)
        {
            //边界处理
            if(dest == arr.size())
            {
                arr[arr.size() - 1] = 0;
                cur--;
             dest -= 2;
            }
            
            break;
        }
        cur++;
    }

    //从后往前
    while (cur >= 0)
    {
        if (arr[cur] == 0)
            arr [dest--] = arr[cur];

        arr [dest--] = arr[cur];

        cur--;
    }
}
};

202. 快乐数

算法原理

这题可以理解为类似链表带环问题,采用“快慢指针”的方法来解决

这里的“快慢指针”是计算数据的跨度,一个每次计算平方,一个每次计算平方的平方(题目已经告诉我们,要么变成1,要么无限循环,当它循环相遇的时候不是1,那么就肯定不是快乐数)

鸽巢原理:

n个巢穴,有n+1个鸽子,那么至少有一个巢穴里面的鸽子数量大于1

int的最大值为例:

image-20230912233931164

代码实现

class Solution
{
public:

int fastQSum(int n)
{
    int tmp = 0;
    int sum = 0;
    while(n)
    {
        tmp = pow((n%10),2)+tmp;
        n=n/10; 
    }
    while(tmp)
    {
        sum = pow((tmp%10),2)+sum;
        tmp = tmp/10;
    }
    return sum;
}
int slowQSum(int n)
{
    int sum = 0;
    while(n)
    {
        sum = pow((n%10),2)+sum;
        n=n/10; 
    }
    return sum;
}
    bool isHappy(int n)
    {
        int slow = slowQSum(n);
        int fast = fastQSum(n);
        while(1)
        {
            if(fast == 1 || slow == 1)
                return true;
            else if(slow == fast && slow!=1)
                return false;
            
            slow = slowQSum(slow);
            fast = fastQSum(fast);
        }
    }
};

11. 盛最多水的容器

算法原理

这里可以采用暴力枚举的方法,将全部的容积算出来,但这里太暴力的,而且可能会超时

所以利用单调性,采用双指针的方法:

image-20230913000411924

代码实现

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

611. 有效三角形的个数

算法原理

三角形判断:2个较小数大于最大数,只需判断一次

这题也可以采用暴力枚举的方法,如果将这个暴力解法采用双指针优化一下,就可以降低一个量级的复杂度

  1. 先排序
  2. 固定最大数
  3. 在最大数的左区间,找出符合的元素

image-20230913001340952

代码实现

class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int m = nums.size()-1;
        int ret = 0;
        while(m>=2)
        {
            int Max = nums[m];
            int left = 0;
            int right = m-1;
            while(left<right)
            {
                int sum = nums[left]+nums[right];
                if(sum>Max)
                {
                    ret += (right-left);
                    right--;
                }
                else
                {
                    left++;
                }
            }
            m--;
        }
        return ret;
    }
};

剑指 Offer 57. 和为s的两个数字

这题较简单,直接看代码:

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

15. 三数之和

算法原理

这里最暴力的方法就是先将元素排序,然后在暴力枚举,将结果放入set去重,但这个只能在比赛或者考试的时候勉强通过,实际还是不建议这样解;

我们还是采用双指针的方法:

  1. 先将数组排序
  2. 然后固定一个数(最左、最右都可以)
  3. 该数的后面/前面区间,找到和为-sum的数即可

细节:

去重操作,找到结果之后,双指针跳过重复的元素;固定值也要跳过重复的元素

代码实现

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        //先排序
        sort(nums.begin(),nums.end());
        vector<vector<int>> ret;
        int n = nums.size();
        int iMin = 0;
        while(iMin<n)
        {
            if(nums[iMin]>0)
                break;

            int left =  iMin+1;
            int right = n-1;
            while(left<right)
            {
                int sum = nums[left]+nums[right];
                int target = -nums[iMin];
                if(sum == target)
                {
                    ret.push_back({nums[iMin],nums[left],nums[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 if(sum<target)
                    left++;
            }
            iMin++;
            //去重
            while(iMin<n && nums[iMin]== nums[iMin-1])
                iMin++;
        }
        return ret;
    }
};

18. 四数之和

原理和三数之和一样,但这里要多一次去重操作;另外,这里的测试用例有溢出值,所以部分位置采用long long类型

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target)
    {
        vector<vector<int>> ret;
        sort(nums.begin(),nums.end());
        int n = nums.size();
        int iMin = 0;
        while(iMin<n)
        {
            //固定值
            int left = iMin+1;
            int right = n-1;
            while(left<right)
            {
                int t = target-nums[iMin];
                int _left = left+1;
                int _right = right;
                while(_left<_right)
                {
                    int sum = nums[_left]+nums[_right];
                    long long _t = (long long)t-nums[left];
                    if(sum == _t)
                    {
                        ret.push_back({nums[iMin],nums[left],nums[_left],nums[_right]});
                        _left++;
                        _right--;
                        while(_left<_right && nums[_left] == nums[_left-1])
                            _left++;
                        while(_left<_right && nums[_right] == nums[_right+1])
                            _right--;
                    }
                    else if(sum<_t)
                        _left++;
                    else if(sum>_t)
                        _right--;
                }
                left++;
                while(left<right && nums[left] == nums[left-1])
                    left++;
            }   

            iMin++;
            while(iMin<n && nums[iMin] == nums[iMin-1])
                iMin++;
        }
        return ret;
    }
};
}
                else if(sum<_t)
                    _left++;
                else if(sum>_t)
                    _right--;
            }
            left++;
            while(left<right && nums[left] == nums[left-1])
                left++;
        }   

        iMin++;
        while(iMin<n && nums[iMin] == nums[iMin-1])
            iMin++;
    }
    return ret;
}

};


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

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

相关文章

MATLAB中ischange函数用法

目录 语法 说明 示例 均值的变化 线性区的变化 矩阵数据 ischange函数的功能是查找数据中的突然变化。 语法 TF ischange(A) TF ischange(A,method) TF ischange(___,dim) TF ischange(___,Name,Value) [TF,S1] ischange(___) [TF,S1,S2] ischange(___) 说明 ​…

Python实现机器学习(下)— 数据预处理、模型训练和模型评估

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。本门课程将介绍人工智能相关概念&#xff0c;重点讲解机器学习原理机器基本算法&#xff08;监督学习及非监督学习&#xff09;。使用python&#xff0c;结合sklearn、Pycharm进行编程&#xff0c;介绍iris&#xff08;鸢尾…

windows10搭建RocketMq

windows10搭建RocketMq 文章目录 windows10搭建RocketMq1.下载二进制RocketMq2.配置环境变量3.启动4.RocketMq控制台安装 1.下载二进制RocketMq 下载链接 2.配置环境变量 变量名:ROCKETMQ_HOME变量值:MQ解压路径 修改runbroker.cmd和runserver.cmd文件 把%CLASSPATH%用引…

SpringBoot + Prometheus + Grafana 打造可视化监控

SpringBoot Prometheus Grafana 打造可视化监控 文章目录 SpringBoot Prometheus Grafana 打造可视化监控常见的监控组件搭配安装Prometheus安装Grafana搭建SpringBoot项目引入依赖示例:监控SpringBoot内置Tomcat线程池的情况grafana创建监控看板 后台SpringBoot服务添加自…

【深度学习】 Python 和 NumPy 系列教程(十):NumPy详解:2、数组操作(索引和切片、形状操作、转置操作、拼接操作)

目录 一、前言 二、实验环境 三、NumPy 0、多维数组对象&#xff08;ndarray&#xff09; 1. 多维数组的属性 1、创建数组 2、数组操作 1. 索引和切片 a. 索引 b. 切片 2. 形状操作 a. 获取数组形状 b. 改变数组形状 c. 展平数组 3. 转置操作 a. 使用.T属性 b…

Redis模块四:常见的数据类型和使用

目录 Redis 的 5 大基础数据类型 ①字符串类型(String) ②字典类型(Hash) ③列表类型(List) ④集合类型(Set) ⑤有序集合类型(ZSet) Redis 的 5 大基础数据类型 String——字符串类型 Hash——字典类型 List——列表类型 Set——集合类型 ZSet——有序集合类型 …

后发而先至的腾讯混元大模型,到底有哪些技术亮点?

2023年的夏天已经结束了&#xff0c;但是&#xff0c;围绕AIGC大模型的关注热度&#xff0c;却丝毫没有衰退的意思。 在过去的大半年里&#xff0c;我们亲眼见证了大模型浪潮的崛起&#xff0c;甚至可以说是疯狂。截止7月&#xff0c;国内的大模型数量&#xff0c;已经超过130个…

MySQL与ES数据同步之异步调用

文章目录 简述SpringBoot项目引入依赖配置文件项目结构实体类配置类RabbitMQ交换机队列声明&#xff0c;绑定配置类回调接口配置类 Mapper接口UserMapper接口UserEsMapper Controller类Service接口Service实现类监听类/消费者 简述 上一篇是同步调用&#xff0c;我们在中间加上…

【海思SS626 | 开发环境】VMware17安装Ubuntu 18.04.6

目录 一、下载 Ubuntu 18.04.6 LTS二、VMware17创建虚拟机三、安装Ubuntu18.04LTS四、安装其他软件五、总结 一、下载 Ubuntu 18.04.6 LTS 问题&#xff1a;为什么要下载 Ubuntu18.04.6 LTS 而不是使用最新的&#xff0c;或者其他Linux发行版&#xff1f; 答&#xff1a;在ss6…

Python 图形化界面基础篇:使用框架( Frame )组织界面

Python 图形化界面基础篇&#xff1a;使用框架&#xff08; Frame &#xff09;组织界面 引言什么是 Tkinter 框架&#xff08; Frame &#xff09;&#xff1f;步骤1&#xff1a;导入 Tkinter 模块步骤2&#xff1a;创建 Tkinter 窗口步骤3&#xff1a;创建框架&#xff08; F…

如何做到安全上网

随着信息化的发展&#xff0c;企业日常办公越来越依赖互联网&#xff0c;而访问互联网过程中&#xff0c;会遇到各种各样不容忽视的风险&#xff0c;例如员工主动故意的数据泄漏&#xff0c;后台应用程序偷偷向外部发信息&#xff0c;木马间谍软件的外联&#xff0c;以及各种挖…

聚观早报 | 荣耀V Purse定档;哪吒S迎来最新OTA升级

【聚观365】9月13日消息 荣耀V Purse定档 哪吒S迎来最新OTA升级 宝马将向其英国工厂投资7.5亿美元 英伟达称霸AI芯片领域致初创公司融资难 甲骨文第一财季收入约125亿美元增长9% 荣耀V Purse定档 不久前&#xff0c;荣耀官方推出了全新的荣耀Magic V2内折叠屏旗舰&#x…

【Linux从入门到精通】信号(信号保存 信号的处理)

本篇文章接着信号&#xff08;初识信号 & 信号的产生&#xff09;进行讲解。学完信号的产生后&#xff0c;我们也了解了信号的一些结论。同时还留下了很多疑问&#xff1a; 上篇文章所说的所有信号产生&#xff0c;最终都要有OS来进行执行&#xff0c;为什么呢&#xff1f;…

在Android studio 创建Flutter项目运行出现问题总结

在Android studio 中配置Flutter出现的问题 A problem occurred configuring root project ‘android’出现这个问题。解决办法 首先找到flutter配置的位置 在D:\xxx\flutter\packages\flutter_tools\gradle位置中的flutter.gradle buildscript { repositories { googl…

相机坐标系 -> 像素坐标系

代码链接&#xff1a;https://github.com/PanJinquan/python-learning-notes/blob/master/modules/utils_3d/camera_tools.py def __cam2pixel(cam_coord, f, c):"""相机坐标系 -> 像素坐标系: (f / dx) * (X / Z) f * (X / Z) / dxcx,ppx260.166; cy,ppy…

分库分表---理论

目录 一、垂直切分 1、垂直分库 2、垂直分表 3、垂直切分优缺点 二、水平切分 1、水平分库 2、水平分表 3、水平切分优缺点 三、数据分片规则 1、Hash取模分表 2、数值Range分表 3、一致性Hash算法 四、分库分表带来的问题 1、分布式事务问题 2、跨节点关联查询…

【FAQ】本地录像视频文件如何推送到视频监控平台EasyCVR进行AI视频智能分析?

安防监控平台EasyCVR支持多协议、多类型设备接入&#xff0c;可以实现多现场的前端摄像头等设备统一集中接入与视频汇聚管理&#xff0c;并能进行视频高清监控、录像、云存储与磁盘阵列存储、检索与回放、级联共享等视频功能。视频汇聚平台既具备传统安防监控、视频监控的视频能…

Vue2电商前台项目——完成Search搜索模块业务

Vue2电商前台项目——完成Search搜索模块业务 Vue基础知识点击此处——Vue.js 文章目录 Vue2电商前台项目——完成Search搜索模块业务一、项目开发的步骤二、各种请求数据并展示数据1、写Search模块的接口2、写Vuex中的search仓库3、组件拿到search仓库的数据&#xff08;1&…

详解HPE MSA 2040存储初始化配置划分卷

哈喽大家好&#xff0c;欢迎来到虚拟化时代君&#xff08;XNHCYL&#xff09;。 “ 大家好&#xff0c;我是虚拟化时代君&#xff0c;一位潜心于互联网的技术宅男。这里每天为你分享各种你感兴趣的技术、教程、软件、资源、福利……&#xff08;每天更新不间断&#xff0c;福…

mock技术在测试中的应用

技术简介 mock技术又叫测试桩、挡板 在软件测试中&#xff0c;对于一些不容易构造、获取的对象&#xff0c;用一个虚拟的对象来代替它&#xff0c;以达到相同的效果&#xff0c;这个虚拟的对象就是mock。 mock技术并不是只有测试领域用&#xff0c;最早是在开发领域应用&…