算法 —— 双指针

news2024/11/23 11:31:59

目录

移动零 

复写零

快乐数

盛最多水的容器

有效三角形的个数

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

三数之和

四数之和


移动零 

 下图以样例1为例,看下图如何做到保证非零元素相对顺序前提下,移动零元素。

 代码实现如下:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        for (int cur = 0, dest = -1; cur < nums.size(); cur++)
            if (nums[cur])//非0就交换
                swap(nums[++dest], nums[cur]);
    }
};

复写零

注意边界情况:例如 [ 1 0 2 3 0 4 ] dest会越界访问,此时需要把cur和dest回归到上一步位置

代码实现如下:

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

        // 2.处理边界情况
        if (dest == n)
        {
            cur--; dest -= 2;
            arr[n - 1] = 0;
        }

        // 3.从后往前遍历完成复写
        while (cur >= 0)
        {
            if (arr[cur])
                arr[dest--] = arr[cur--];
            else
            {
                arr[dest--] = 0;
                arr[dest--] = 0;
                cur--;
            }
        }
    }
};

快乐数

先看示例2为什么会输出false:

此题目一共三种情况:1、进入全是1的环     2、进入全部不是1的环     3、无限延伸下去不带环

但是题目告诉我们只有两种情况,为什么不会无限延伸下去,可以用鸽巢原理解释:

鸽巢原理: 把(n+1)个物体任意放进n个鸽巢中(n是非0自然数),一定有一个鸽巢中至少放进了2个物体。 

题目给出范围n最大为2 ^ 31 - 1,即 2.1 * 10 ^ 9,假设是9999999999,那么经过一次平方和后变成810,也就是说n最大值经过一次平方和后最大不超过810,最小不低于1。

那么把810看作巢穴,把一次平方和规则看作鸽,经过811次平方和后,会导致810个巢穴不够分,至少有一个巢穴是两个鸽:意味着经过810次以上的平方和规则后,势必出现重复,重复后就进环。

代码入下:

class Solution {
public:
    // 计算每个位置上的数字的平方和
    int summary(int n)
    {
        int sum = 0;
        while (n)
        {
            int tmp = n % 10;
            sum += tmp * tmp;
            n /= 10;
        }
        return sum;
    }

    bool isHappy(int n) {
        int slow = n, fast = summary(n);
        // 快指针走两步  慢指针走一步
        while (slow != fast)
        {
            slow = summary(slow);
            fast = summary(summary(fast));
        }
        return slow == 1;
    }
};

盛最多水的容器

 设置两个左右指针,由于下标相减所得宽度是不断减小的,那么在有限长度内,保证宽度最大的前提下得到最大的长度

宽度变小,长度可能不变,也可能变小,根据上图得出以下代码:

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

有效三角形的个数

 首先先对数组进行排序,例如 a , b , c 现在是升序状态,两个比c小的数相加大于c,那么c 加两个小数中的任何一个小数都比另外一个小数大。此外暴力枚举的时间复杂度过大,本题不适合。

首先固定最大的数,以一个循环为例,先固定最大数10,左指针指向下标为0的元素(2),右指针指向下标为5的元素(9),a就是2,b就是9,c就是10,a + b > c,那么a——b这个区间里所有数加b都大于c,个数即为right - left。一轮过后,right--找到次小的数5,再使left从下标0开始,a + b小于c,那么让left++,使得left变大,如果left == right时还小于最大数10,说明剩下的数无法组合成三角形,接着固定9作为最大数c,循环上述步骤。

代码如下:

class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        // 1.优化排序
        sort(nums.begin(), nums.end());

        // 2.利用双指针解决问题
        int count = 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])
                {
                    count += (right - left);
                    right--;
                }
                else
                    left++;
            }
        }
        return count;
    }
};

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

首先最重要一点:题目告诉我们此数组为升序,那么可以利用单调性来解决问题。 

左指针右移相当于做加法操作,因为指向了一个更大的数,同理右指针左移相当于做减法操作,因为指向了一个更小的数。代码实现如下:

class Solution {
public:
    vector<int> twoSum(vector<int>& price, int target) {
        vector<int> ret;
        int left = 0, right = price.size() - 1;
        while (left < right)
        {
            int sum = price[left] + price[right];
            // 右指针左移相当于做减法
            if (sum > target)
                right--;
            // 左指针右移相当于做加法
            else if (sum < target)
                left++;
            else
            {
                ret.push_back(price[left]);
                ret.push_back(price[right]);
                break;
            }
        }
        return ret;
    }
};

三数之和

 此题最关键的为去重问题和避免越界问题,那么如何避免这两个问题发生呢?

首先要保证left指针始终在right左边,然后left++或者right--之后才可以和left前一个数或者right后一个数比较,并且 i 始终小于该数组元素个数。

代码实现如下:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ret;

        // 1.排序
        sort(nums.begin(), nums.end());

        // 2.利用双指针解决问题
        for (int i = 0; i < nums.size() - 2;)
        {
            // 大于0意味着后面全是正数   不可能相加为0
            if (nums[i] > 0)
                break;
            int left = i + 1, right = nums.size() - 1, target = -nums[i];
            while (left < right)
            {
                vector<int> ans;
                int sum = nums[left] + nums[right];
                if (sum > target)
                {
                    right--;
                }
                else if (sum < target)
                {
                    left++;
                }
                else
                {
                    ans.push_back(nums[i]);
                    ans.push_back(nums[left]);
                    ans.push_back(nums[right]);
                    ret.push_back(ans);
                    left++; right--;

                    // 去重 left 和 right
                    while (left < right && nums[left] == nums[left - 1])
                        left++;
                    while (left < right && nums[right] == nums[right + 1])
                        right--;
                }
            }
            // 去重 i
            i++;
            while (i < nums.size() && nums[i] == nums[i - 1])
                i++;
        }
        return ret;
    }
};

四数之和

 此题唯一有问题的地方在于数据的大小可能会超过int类型的最大值,那么我们需要将他强制类型转换成long long类型的数据,这样便于后面的比较。其余部分和三数之和并无多大区别。

代码如下:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        // 1.排序
        sort(nums.begin(), nums.end());

        // 2.利用双指针解决问题
        vector<vector<int>> ret;

        // 解决特殊情况   
        // 1.1 特殊情况  元素个数小于4
        if (nums.size() < 4)
            return ret;

        for (int a = 0; a < nums.size() - 3;) // 固定数 a
        {
            for (int b = a + 1; b < nums.size() - 2;) // 固定数 b
            {        
                // 1.2 特殊情况  数据溢出
                long long my_target = (long long)target - nums[a] - nums[b];
                int left = b + 1, right = nums.size() - 1;
                while (left < right)
                {
                    int sum = nums[left] + nums[right];
                    if (sum > my_target)
                        right--;
                    else if (sum < my_target)
                        left++;
                    else
                    {
                        ret.push_back({ nums[a],nums[b],nums[left],nums[right] });
                        left++; right--;
                        // 去重 left 和 right
                        while (left < right && nums[left] == nums[left - 1])
                            left++;
                        while (left < right && nums[right] == nums[right + 1])
                            right--;
                    }
                }
                // 去重 b
                b++;
                while (b < nums.size() && nums[b] == nums[b - 1])
                    b++;
            }
            // 去重 a
            a++;
            while (a < nums.size() && nums[a] == nums[a - 1])
                a++;
        }
        return ret;
    }
};

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

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

相关文章

1,Windows-本地Linux 系统(WSL)

目录 第一步电脑设置 第二步安装Ubuntu 第三文件传递 开发人员可以在 Windows 计算机上同时访问 Windows 和 Linux 的强大功能。 通过适用于 Linux 的 Windows 子系统 (WSL)&#xff0c;开发人员可以安装 Linux 发行版&#xff08;例如 Ubuntu、OpenSUSE、Kali、Debian、Arc…

如何有效保护生物医药企业隔离网数据导出的安全性?

生物医药企业的核心数据保护至关重要&#xff0c;企业为了保护内部的核心数据&#xff0c;会将网络进行物理隔离&#xff0c;将企业内⽹与外⽹隔离。⽹络隔离后&#xff0c;仍存在重要数据从内网导出至外网的隔离网数据导出需求。以下是一些需要特别保护的核心数据类型&#xf…

小米平板6系列对比

小米平板6系列目前有4款&#xff0c;分别为6、6 Pro、6 Max、6S Pro。具体对比如下表所示。 小米平板型号66 Pro6 Max6S Pro实物图发布时间2023年4月21日2023年4月21日2023年8月14日2024年2月22 日屏幕大小11英寸11英寸14英寸12.4英寸分辨率2.8K2.8K2.8K3K刷新率144Hz144Hz120…

EtherCAT笔记(四)——EtherCAT数据帧结构

EtherCAT数据包含2B的数据头和44~1948B的数据区。数据区由多个子报文组成。由于EtherCAT本身是通过以太网数据帧的形式传输&#xff0c;因此其协议帧中会携带以太网的帧头。 其中&#xff0c;解释如下&#xff1a; &#xff08;1&#xff09;以太网数据帧头&#xff1a;EtherC…

VSCode + GDB + J-Link 单片机程序调试实践

VSCode GDB J-Link 单片机程序调试实践 本文介绍如何创建VSCode的调试配置&#xff0c;如何控制调试过程&#xff0c;如何查看修改各种变量。 安装调试插件 在 VSCode 扩展窗口搜索安装 Cortex-Debug插件 创建调试配置 在 Run and Debug 窗口点击 create a launch.json …

C语言力扣刷题11——打家劫舍1——[线性动态规划]

力扣刷题11——打家劫舍1和2——[线性动态规划] 一、博客声明二、题目描述三、解题思路1、线性动态规划 a、什么是动态规划 2、思路说明 四、解题代码&#xff08;附注释&#xff09; 一、博客声明 找工作逃不过刷题&#xff0c;为了更好的督促自己学习以及理解力扣大佬们的解…

日志分析-windows系统日志分析

日志分析-windows系统日志分析 使用事件查看器分析Windows系统日志 cmd命令 eventvwr 筛选 清除日志、注销并重新登陆&#xff0c;查看日志情况 Windows7和Windowserver2008R2的主机日志保存在C:\Windows\System32\winevt\Logs文件夹下&#xff0c;Security.evtx即为W…

有哪些防爬虫的方法

防爬虫的方法有robots.txt文、user-agent过滤、ip限制、验证码、动态页面生成、频率限制、动态url参数和反爬虫技术等。详细介绍&#xff1a;1、robots.txt文件&#xff0c;用于告诉搜索引擎爬虫哪些页面可以访问&#xff0c;哪些页面禁止访问&#xff1b;2、ip限制&#xff0c…

面试-J.U.C包的梳理

1.J.U.C包的梳理 Java.Util.Concurrent包简称JUC (1)JUC整体架构图 (2)分析 Executor&#xff1a;线程执行器&#xff0c;任务执行和调度的框架。Tools下存在executor相关的executors类&#xff0c;用于创建executorservice&#xff0c;scheduleexecutorservice&#xff0c;…

获取 url 地址栏 ? 后面的查询字符串,并以键值对形式放到对象里面

写在前面 在前端面试当中&#xff0c;关于 url 相关的问题很常见&#xff0c;而对于 url 请求参数的问题也很常见&#xff0c;大部分以笔试题常见&#xff0c;今天就根据这道面试题一起来看一下。 问题 获取 url 地址栏?后面的查询字符串&#xff0c;并以键值对形式放到对象…

CICD持续集成(Jenkins+Git+Gogs)

1.Jenkins Jenkins 是一个开源的、用于构建和自动化软件开发流程的持续集成和交付工具。它提供了一个可扩展的平台&#xff0c;用于构建、测试和部署软件项目。通过使用 Jenkins&#xff0c;开发团队可以实现持续集成和交付&#xff0c;自动化构建和测试过程&#xff0c;提高软…

Rust监控可观测性

可观测性 在监控章节的引言中&#xff0c;我们提到了老板、前端、后端眼中的监控是各不相同的&#xff0c;那么有没有办法将监控模型进行抽象、统一呢&#xff1f; 来简单分析一下&#xff1a; 业务指标实时展示&#xff0c;这是一个指标型的数据( metric )手机 APP 上传的数…

springboot在线考试 LW +PPT+源码+讲解

第三章 系统分析 3.1 可行性分析 一个完整的系统&#xff0c;可行性分析是必须要有的&#xff0c;因为他关系到系统生存问题&#xff0c;对开发的意义进行分析&#xff0c;能否通过本系统来补充线下在线考试管理模式中的缺限&#xff0c;去解决其中的不足等&#xff0c;通过对…

三让徐州 | 第8集 | 自古皆有死,人无信不立 | 三国演义 | 逐鹿群雄

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 &#x1f4cc;这篇博客分享的是《三国演义》文学剧本第Ⅰ部分《群雄逐鹿》的第8️⃣集《三让徐州》的经典语句和文学剧本全集台词 文章目录 1.经典语句2.文学剧本台词…

通过Python脚本实现字符画

效果 讲解&#xff1a; 用于将3D视图的帧缓冲区转换为字符画&#xff0c;并将字符画输出到文本编辑器中。 首先&#xff0c;获取当前绑定的帧缓冲区、视口信息和视图像素。 然后&#xff0c;将像素矩阵转化为字符串&#xff0c;并将字符串写入到文本编辑器中。 设置文本编辑…

【软件测试】白盒测试(知识点 + 习题 + 答案)

《 软件测试基础持续更新中》 最近大家总是催更……&#xff0c;我也是百忙之中给大家详细总结了白盒测试的重点内容&#xff01; 知识点题型答案&#xff0c;让你用最短的时间&#xff0c;学到最高效的知识&#xff01; 整理不易&#xff0c;求个三连 ₍ᐢ..ᐢ₎ ♡ 目录 一、…

Oracle数据库使用指南基本概念

学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中……&#xff09; 4、牛逼哄哄的 IDEA编程利器技巧(编写中……&#xff09; 5、面经吐血整理的 面试技…

将深度相机的实时三维坐标数据保存为excel文档

一、如何将数据保存为excel文档 1.excel文件库与相关使用 &#xff08;1&#xff09;导入相应的excel文件库&#xff0c;导入前先要进行pip安装&#xff0c;pip install xlwt import xlwt # 导入用于创建和写入Excel文件的库 (2) 建立一个excel文档&#xff0c;并在第0行写…

PyQt问题汇总(持续更新)

目录 1.抛出异常后QAppliaction自动闪退 2.Unbuntu共享文件夹自动挂载 1.抛出异常后QAppliaction自动闪退 开发阶段&#xff0c;PyQt5 QAppliaction会在遇到未捕获的异常时立即退出&#xff0c;它能够快速发现并报告错误&#xff0c;我在调用一些密码算法库的时候&#xff0…

利用SHAP算法解释BERT模型的输出

1 何为SHAP? 传统的 feature importance 只告诉哪个特征重要&#xff0c;但并不清楚该特征如何影响预测结果。SHAP 算法的最大优势是能反应每一个样本中特征的影响力&#xff0c;且可表现出影响的正负性。SHAP算法的主要思想为&#xff1a;控制变量法&#xff0c;如果某个特征…