【优选算法之双指针】No.2--- 经典双指针算法(下)

news2024/9/21 22:09:20

文章目录

  • 前言
  • 一、双指针示例:
    • 1.1 ⽔果成篮
    • 1.2 和为s的两个数字
    • 1.3 三数之和
    • 1.4 四数之和
  • 二、双指针总结:


前言

在这里插入图片描述

👧个人主页:@小沈YO.
😚小编介绍:欢迎来到我的乱七八糟小星球🌝
📋专栏:优选算法
🔑本章内容:双指针
记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~


提示:以下是本篇文章正文内容,下面案例可供参考

一、双指针示例:

1.1 ⽔果成篮

  1. 题⽬链接:611. 有效三⻆形的个数
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法⼀(暴⼒求解)(会超时):
    算法思路:三层 for 循环枚举出所有的三元组,并且判断是否能构成三⻆形。
    虽然说是暴⼒求解,但是还是想优化⼀下:
    判断三⻆形的优化:
  • 如果能构成三⻆形,需要满⾜任意两边之和要⼤于第三边。但是实际上只需让较⼩的两条边之和⼤于第三边即可。
  • 因此我们可以先将原数组排序,然后从⼩到⼤枚举三元组,⼀⽅⾯省去枚举的数量,另⼀⽅⾯⽅便判断是否能构成三⻆形
  1. 解法⼆(排序 + 双指针):
    算法思路:先将数组排序。
    根据「解法⼀」中的优化思想,我们可以固定⼀个「最⻓边」,然后在⽐这条边⼩的有序数组中找出⼀个⼆元组,使这个⼆元组之和⼤于这个最⻓边。由于数组是有序的,我们可以利⽤「对撞指针」来优化。
    设最⻓边枚举到 i 位置,区间 [left, right] 是 i 位置左边的区间(也就是⽐它⼩的区间):
    ◦ 如果 nums[left] + nums[right] > nums[i] :
    ▪ 说明 [left, right - 1] 区间上的所有元素均可以与 nums[right] 构成⽐ nums[i] ⼤的⼆元组
    ▪ 满⾜条件的有 right - left 种
    ▪ 此时 right 位置的元素的所有情况相当于全部考虑完毕, right-- ,进⼊下⼀轮判断
    ◦ 如果 nums[left] + nums[right] <= nums[i] :
    ▪ 说明 left 位置的元素是不可能与 [left + 1, right] 位置上的元素构成满⾜条件的⼆元组
    ▪ left 位置的元素可以舍去, left++ 进⼊下轮循环
  2. C++代码(数组模拟哈希/容器)
class Solution {
public:
    int triangleNumber(vector<int>& nums) 
    {

        int cnt=0;
        sort(nums.begin(),nums.end());
        if(nums.size()<3)return 0;
        for(int i=nums.size()-1;i>=2;i--)
        {
            int left=0,right=i-1;
            while(left<right)
            {
                if(nums[left]+nums[right]>nums[i])
                {
                    cnt+=right-left;
                    right--;
                }
                else
                {
                    left++;
                }
            }
        }
        return cnt;
    }
};

1.2 和为s的两个数字

  1. 题⽬链接: 剑指 Offer 57. 和为s的两个数字

  2. 题⽬描述:
    在这里插入图片描述

  3. 解法⼀(暴⼒解法,会超时):
    算法思路:两层 for 循环列出所有两个数字的组合,判断是否等于⽬标值。
    算法流程:
    两层 for 循环:
    ◦ 外层 for 循环依次枚举第⼀个数 a ;
    ◦ 内层 for 循环依次枚举第⼆个数 b ,让它与 a 匹配;
    ps :这⾥有个魔⻤细节:我们挑选第⼆个数的时候,可以不从第⼀个数开始选,因为 a 前⾯的数我们都已经在之前考虑过了;因此,我们可以从 a 往后的数开始列举。
    ◦ 然后将挑选的两个数相加,判断是否符合⽬标值

  4. 解法⼆(双指针 - 对撞指针):
    算法思路:
    注意到本题是升序的数组,因此可以⽤「对撞指针」优化时间复杂度。算法流程(附带算法分析,为什么可以使⽤对撞指针):
    a. 初始化 left , right 分别指向数组的左右两端(这⾥不是我们理解的指针,⽽是数组的下标)
    b. 当 left < right 的时候,⼀直循环
    i. 当 array[left] + array[right] == sum时,说明找到结果,记录结果,并且返回;
    ii. 当 array[left] + array[right] < sum时:
    • 对于 array[left] ⽽⾔,此时 array[right] 相当于是 array[left] 能碰到的最⼤值(别忘了,这⾥是升序数组哈~)。如果此时不符合要求,说明在这个数组⾥⾯,没有别的数符合 nums[left] 的要求了(最⼤的数都满⾜不了你,你已经没救了)。因此,我们可以⼤胆舍去这个数,让 left++ ,去⽐较下⼀组数据;
    • 那对于 array[right] ⽽⾔,由于此时两数之和是⼩于⽬标值的, array[right] 还可以选择⽐ array[left] ⼤的值继续努⼒达到⽬标值,因此 right 指针我们按兵不动;
    iii. 当 array[left] + array[right] > sum时,同理我们可以舍去 array[right] (最⼩的数都满⾜不了你,你也没救了)。让 right-- ,继续⽐较下⼀组数据,⽽ left 指针不变(因为他还是可以去匹配⽐ array[right] 更⼩的数的)

  5. C++代码

class Solution {
public:
    vector<int> FindNumbersWithSum(vector<int> array,int sum) 
    {
        sort(array.begin(),array.end());
        vector<int> v;
        int left=0,right=array.size()-1;
        while(left<right)
        {
            if(array[left]+array[right]<sum)
            left++;
            else if(array[left]+array[right]>sum)right--;
            else
            {
                v.push_back(array[left]);
                v.push_back(array[right]);
                break;
            }
        }
        return v;
    }
};

1.3 三数之和

  1. 题⽬链接:15. 三数之和

  2. 题⽬描述:
    在这里插入图片描述

  3. 解法(排序+双指针):
    算法思路:本题与两数之和类似,是⾮常经典的⾯试题
    与两数之和稍微不同的是,题⽬中要求找到所有「不重复」的三元组。那我们可以利⽤在两数之和那⾥⽤的双指针思想,来对我们的暴⼒枚举做优化:
    i. 先排序;
    ii. 然后固定⼀个数 a :
    iii. 在这个数后⾯的区间内,使⽤「双指针算法」快速找到两个数之和等于 -a 即可。
    但是要注意的是,这道题⾥⾯需要有「去重」操作~
    i. 找到⼀个结果之后, left 和 right 指针要「跳过重复」的元素;
    ii. 当使⽤完⼀次双指针算法之后,固定的 a 也要「跳过重复」的元素

  4. C++代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) 
    {
        vector<vector<int>> vv;
        sort(nums.begin(),nums.end());
        set<vector<int>> sv;
        for(int i=nums.size()-1;i>=2;)
        {
            int left=0,right=i-1;
            while(left<right)
            {
                if(nums[left]+nums[right]<(-nums[i]))
                {
                    left++;
                }
                else if(nums[left]+nums[right]>(-nums[i]))
                {
                    right--;
                }
                else
                {
                    vv.push_back({nums[left],nums[right],nums[i]});
                    left++;right--;
                    while(left<right&&nums[left]==nums[left-1])
                    left++;
                    while(left<right&&nums[right]==nums[right+1])
                    right--;
                }
            }
            i--;
            while(i>=2&&nums[i]==nums[i+1])i--;
        }
        return vv;
    }
};

1.4 四数之和

  1. 题⽬链接:18. 四数之和
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(排序 + 双指针)
    算法思路:
    a. 依次固定⼀个数 a ;
    b. 在这个数 a 的后⾯区间上,利⽤「三数之和」找到三个数,使这三个数的和等于 target- a 即可。
  4. C++代码
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) 
    {
        vector<vector<int>> vv;
        if(nums.size()<4)return vv;
        sort(nums.begin(),nums.end());
        for(int dest=nums.size()-1,cur=dest-1;dest>=3;)
        {
            while(cur>=2)
            {
                int left=0,right=cur-1;
                while(left<right)
                {
                    long long sum=nums[left]+nums[right];
                    long long tmp=(long long)target-nums[dest]-nums[cur];
                    if(sum<tmp)
                    {
                        left++;
                    }
                    else if(sum>tmp)
                    {
                        right--;
                    }
                    else
                    {
                        vv.push_back({nums[left],nums[right],nums[cur],nums[dest]});
                        left++;
                        right--;
                        while(left<right&&nums[right]==nums[right+1])right--;
                        while(left<right&&nums[left]==nums[left-1])left++;
                    }
                }
                cur--;
                while(cur>=2&&nums[cur]==nums[cur+1])cur--;
            }
            dest--;
            while(dest>=3&&nums[dest]==nums[dest+1])dest--;
            cur=dest-1;
        }
        return vv;
    }
};

二、双指针总结:

  • 1.移动零:快排的思想:数组划分区间 - 数组分两块
  • 2.复写零:从后往前(涉及到覆盖的)
  • 3.快乐数:快慢指针(设计循环)
  • 4.盛水最多的容器:对撞指针
  • 5.有效三角的个数:固定一边+对撞指针
  • 6.和为S的两个数字:排序+对撞指针
  • 7.三数之和:排序+对撞指针+固定
  • 8.四数之和:排序+对撞指针(三指针)+固定

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

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

相关文章

前后端分离,使用MOCK进行数据模拟开发,让前端攻城师独立于后端进行开发

mock是什么 Mock生成随机数据,拦截Ajax 请求&#xff0c;前后端分离&#xff0c;让前端攻城师独立于后端进行开发。 增加单元测试的真实性 通过随机数据,模拟各种场景。 在实际开发过程中&#xff0c;前端是通过axios来请求数据的&#xff0c;很多时候前端开发者就是通过写固定…

【Git必看系列】—— Git巨好用的神器之git stash篇

应用场景 当我们开发一个新功能时会先从master拉出一个分支dev&#xff0c;然后在这个dev分支下吭哧吭哧的开始写代码开发新功能&#xff0c;就如下代码所示&#xff0c;我们在dev分支下开发Person类的新功能getId() public class Person {private int id;private String nam…

Vue3:v-model实现组件通信

目录 一.性质 1.双向绑定 2.语法糖 3.响应式系统 4.灵活性 5.可配置性 6.多属性绑定 7.修饰符支持 8.defineModel使用 二.使用 1.父组件 2.子组件 三.代码 1.父组件代码 2.子组件代码 四.效果 一.性质 在Vue3中&#xff0c;v-model指令的性质和作用主要体现在…

vue3 快速入门系列 —— 基础

基础 前面我们已经用 vue2 和 react 做过开发了。 AIAutoPrediction 从 vue2 升级到 vue3 成本较大&#xff0c;特别是较大的项目。所以许多公司对旧项目继续使用vue2&#xff0c;新项目则使用 vue3。 有些UI框架&#xff0c;比如ant design vue1.x 使用的 vue2。但现在 an…

5.C++面向对象2(类对象大小计算,结构体内存对齐,大小端存储方式,this指针)

⭐本篇文章为C学习第4章&#xff0c;主要了解类对象大小和this指针 ⭐本人C代码仓库&#xff1a;yzc的c学习: 小川c的学习记录 - Gitee.com 目录 一. 类对象模型 1.1 类成员函数和成员变量的分布 1.2 如何计算类的大小&#xff1f;&#xff08;结构体内存对齐&#xff09…

卸载node,安装nvm的详细使用方法

一、nvm是什么&#xff1f; nvm是一个node的版本管理工具&#xff0c;可以简单切换的node版本、安装、查看。。。等等&#xff0c;与npm不同的是&#xff0c;npm是依赖包的管理工具。 二、nvm下载安装 安装之前需要先把 自己电脑上边的node给卸载了&#xff0c;不然安装不好…

【数据结构初阶】链式二叉树接口实现超详解

文章目录 1. 节点定义2. 前中后序遍历2. 1 遍历规则2. 2 遍历实现2. 3 结点个数2. 3. 1 二叉树节点个数2. 3. 2 二叉树叶子节点个数2. 3. 3 二叉树第k层节点个数 2. 4 二叉树查找值为x的节点2. 5 二叉树层序遍历2. 6 判断二叉树是否是完全二叉树 3. 二叉树性质 1. 节点定义 用…

日志系统第三弹:日志消息和格式化模块的实现

日志系统第三弹&#xff1a;日志消息和格式化模块的实现 一、日志消息模块的实现二、日志格式化模块的设计1.格式化占位符的约定2.如何打印1.各种零件类1.抽象类2.简单的零件类3.日期零件类4.非格式化数据零件类 2.Formatter 3.如何解析 三、日志格式化模块的实现1.解析函数2.c…

一文详解Unity下RTMP推送|轻量级RTSP服务|RTSP|RTMP播放模块说明

技术背景 好多开发者&#xff0c;对Unity下的模块&#xff0c;不甚了解&#xff0c;实际上&#xff0c;除了Windows/Linux/Android/iOS Native SDK&#xff0c;大牛直播SDK发布了Unity环境下的RTMP推流|轻量级RTSP服务&#xff08;Windows平台Linux平台Android平台&#xff09…

Windows安装Oracle11gR2(图文教程)

本章教程&#xff0c;记录在Windows10上安装Oracle11gR2过程。 一、下载安装包 通过网盘分享的文件&#xff1a;oracle11g 链接: https://pan.baidu.com/s/15ilciQ5NlKWtClklmdAH_w?pwds4dd 提取码: s4dd 二、下载并解压文件 将网盘中的安装包文件下载到本地&#xff0c;在此之…

谷歌收录查询工具,好用的谷歌收录查询工具应具备的这5个特性

在探讨如何高效利用谷歌收录查询工具以优化网站可见性和搜索引擎排名时&#xff0c;好用这一标准往往涵盖了工具的准确性、易用性、功能全面性以及对搜索引擎算法变化的适应性等多个方面。 1.准确性 首先&#xff0c;一款好用的谷歌收录查询工具必须能够提供高度准确的数…

C Prime Plus 第6章习题

你该逆袭了 红色标注的是&#xff1a;错误的答案 蓝色标注的是&#xff1a;正确的答案 绿色标注的是&#xff1a;做题时有疑问的地方 橙色标注的是&#xff1a;答案中需要着重注意的地方 练习题 一、复习题1、2、3、4、5、我的答案&#xff1a;错误正确答案&#xff1a; 6、7、…

窥探 引用拷贝、浅拷贝、深拷贝 的那些事 (clone版)

谁家玉笛暗飞声 散入春风满洛城 往期回顾✨内部类 目录✨ 引用拷贝 介绍 总结 浅拷贝 介绍 浅拷贝的步骤 深拷贝 介绍 引用拷贝 介绍 引用拷贝就是我们常用的 “赋值” &#xff0c;只是复制了原对象的引用&#xff0c;即两个对象指向同一块内存堆地址。修改其中的一个对象会影…

【图灵完备 Turing Complete】游戏经验攻略分享 Part.6 处理器架构2 函数

新的架构来了&#xff0c;本游戏的最后一个攻略分享&#xff0c;最后汇编部分无非是对于操作码的熟练&#xff0c;硬件没有问题&#xff0c;那么也就无关痛痒了。 汇编实现&#xff0c;两数相或和两数相与非一起相与即可。 八位异或器&#xff0c;整就完事了。 有手就行。 利…

【梯度下降算法学习笔记】

梯度下降单参数求解 经过之前的学习我们来引入梯度下降的理念 α \alpha α为学习率 w 1 w 初 − α ∂ J ( w ) ∂ w w_1w_初-\alpha\frac{\partial J(w)}{\partial w} w1​w初​−α∂w∂J(w)​ w 2 w 1 − α ∂ J ( w 1 ) ∂ w 1 w_2w_1-\alpha\frac{\partial J(w_1)}…

国庆电影扎堆来袭,AI智能体帮你推荐必看佳片!(附制作教程)

大家好&#xff0c;我是凡人。 今天看到新闻&#xff0c;发现国庆有10部影片要扎堆儿上映&#xff0c;对于选择困难症的我属实有点难选&#xff0c;同时也想避开一些坑省的浪费金钱和时间。 本着不知道就问AI的习惯&#xff0c;想问问大模型怎么看&#xff0c;但做了简单的交…

MySQL 优化器:理解与探秘

在 MySQL 数据库的世界里&#xff0c;优化器扮演着至关重要的角色。它就像是一位幕后的魔法师&#xff0c;默默地为数据库的高效运行贡献着力量。那么&#xff0c;MySQL 优化器究竟是什么&#xff1f;它又是如何工作的呢&#xff1f;让我们一起来揭开它的神秘面纱。 一、MySQL…

行业人工智能研究-Python自监督方式学习图像表示算法

学术界人工智能研究落后于工业界 摘要 行业或工业界在人工智能研究上超出学术界&#xff0c;并占据着大量的计算力&#xff0c;数据集和人才诱人的薪水和明朗的预期吸引大量人才离开学术界&#xff0c;涌入行业或工业界即使&#xff0c;比如Meta开源其人工智能模型&#xff0…

二分查找算法(1) _二分查找_模板

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 二分查找算法(1) _二分查找模板 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 1. 二…

掌握Android开发新趋势:Jetpack与现代架构技术全解析

随着Android开发技术的不断进步&#xff0c;Jetpack和现代架构技术已成为构建高效、可维护应用的关键。本文将为您介绍一套全面的学习资料&#xff0c;包括大纲、PDF文档、源代码以及学习视频&#xff0c;帮助您深入理解Jetpack核心库、架构组件以及现代开发工具。 内容&#…