算法练习:双指针

news2024/11/18 3:45:23

目录

  • 1. 双指针
    • 1.1 移动 "0"
    • 1.2 复写 "0"
    • 1.3 快乐数(快慢指针)
    • 1.4 盛水最多的容器(单调性原则)
    • 1.5 有效三角形个数
    • 1.6 两个数之和
    • 1.7 三数之和
    • 1.8 四数之和

1. 双指针

1.1 移动 “0”

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    移动 “0”

思路演示:
在这里插入图片描述

补充:

  1. [0, dest]区间内的元素都为0
  2. [dest + 1, cur]区间内的元素都不为0
  3. cur指针遍历完数据,调整结束
class Solution 
{
public:
    void moveZeroes(vector<int>& nums) 
    {
        int dest = -1;
        int cur = 0;
        while(cur < nums.size())
        {
            if(nums[cur])
            {
                swap(nums[cur], nums[++dest]);
            }
            cur++;
        }
    }
};

1.2 复写 “0”

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    复写"0"

思路演示:
在这里插入图片描述
在这里插入图片描述

注意:

  1. 寻找最后未覆盖结点时可能回导致dest越界,从而导致逆向复写的过程中出现越界错误。
    例:[0, 0, 0]
    因此,需要对此种越界情况做特殊处理。
class Solution 
{
public:
    void duplicateZeros(vector<int>& arr) 
    {
        //找结点
        int cur = -1;
        int dest = -1;
        int size = arr.size();
        while (dest < size - 1)
        {
            cur++;
            if (arr[cur] == 0)
            {
                dest += 2;
            }
            else
            {
                dest++;
            }
        }

        //越界可能
        while(cur >= 0)
        {
            if(arr[cur] == 0)
            {
            	//特殊处理
                if(dest > size - 1)
                {
                    arr[--dest] = arr[cur];
                }
                else
                {
                    arr[dest] = arr[cur];
                    arr[--dest] = arr[cur];
                }
            }
            else
            {
            	//特殊处理
                if(dest > size - 1)
                {
                    arr[--dest] = arr[cur];
                }
                else
                {
                    arr[dest] = arr[cur];
                }
            }

            dest--;
            cur--;
        }

    }
};

1.3 快乐数(快慢指针)

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    快乐数

过程演示:
在这里插入图片描述

注: 无论数n是否为快乐数,其进行快乐数的判断逻辑一定都会进入一个循环。我们将每次运算得出的结果视为结点,平方和的运算步骤视为链表的一步。那么,上述问题就可以理解为链表循环问题。(是否为只有1的环)

class Solution 
{
public:
    int gethappy(int num)
    {
        int sum = 0;
        while(num)
        {
            sum += (num % 10) * (num % 10);
            num /= 10;
        }

        return sum;
    }

    bool isHappy(int n) 
    {
        //环状链表,快慢指针
        int quick = n;
        int slow = n;

        do
        {
        	//快慢指针
        	//走一步
            slow = gethappy(slow);
			//走两步
            quick = gethappy(quick);
            quick = gethappy(quick);
        }while(slow != quick);

        if(slow == 1)
        {
            return true;
        }

        return false;
    }
};

1.4 盛水最多的容器(单调性原则)

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    盛水最多的容器

过程演示:

思路1:求出所有的容积,然后在其中选出最大(暴力求解)

思路2:单调性原则

在这里插入图片描述

  1. 容器的的高是由短边决定的
  2. 因此可以确定在高不变的情况下,移动长边只会导致底变短
  3. 所以可以确定当前的搭配是以短边为高一组中,容积最大的

只需记录每组中最大的容积,算法时间复杂度优化为O(n)

class Solution {
public:
    int maxArea(vector<int>& height) 
    {
        //单调性原则
        //将小边丢掉
        int left = 0;
        int right = height.size() - 1;
        vector<int> area;
        while(left < right)
        {
            if(height[left] < height[right])
            {
                area.push_back((right - left) * height[left]);
                left++;
            }
            else
            {
                area.push_back((right - left) * height[right]);
                right--;
            }
        }

        int max = area[0];
        for(auto e : area)
        {
            if(e > max)
            {
                max = e;
            }
        }

        return max;
    }
};

1.5 有效三角形个数

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    有效三角形个数
  3. 思路:
    <1> 先将所给数组进行排序(升序)
    <2> 判断三个数是否能够组成三角形的三个边:任意两边之和大于第三边
    <3> 指针对撞法(优化暴力求解)

过程演示:
在这里插入图片描述

class Solution 
{
public:
    int triangleNumber(vector<int>& nums) 
    {
        //任意两边之和大于第三边
        //优化先排序再判断
        sort(nums.begin(), nums.end());
        
        int times = 0;

        int count = nums.size() - 1;
        int left = 0;
        int right = count - 1; 
        while(count >= 2)
        {
            while(right >= 1)
            {
                while(left < right && nums[right] + nums[left] <= nums[count])
                {
                    left++;
                }
                
                if(left < right)
                {
                    times += (right - left);
                }

                right--;
            }

            left = 0;
            count--;
            right = count - 1;
        }

        return times;
    }
};

1.6 两个数之和

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    两数之和
  3. 思路:
    <1> 若两数之和大于等于指定数,移动右指针
    <2> 若两数之和小于指定数,移动左指针
    直至两指针相撞

过程演示:
在这里插入图片描述

class Solution 
{
public:
    vector<int> twoSum(vector<int>& price, int target) 
    {
        vector<int> goods;
        //大挪右,小挪左
        int left = 0;
        int right =price.size() - 1;
        while(left < right && price[left] + price[right] != target)
        {
            if(price[left] + price[right] > target)
            {
                right--;
            }
            
            if(price[left] + price[right] < target)
            {
                left++;
            }
        }

        if(left < right)
        {
            goods.push_back(price[left]);
            goods.push_back(price[right]);
        }

        return goods;
    }
};

1.7 三数之和

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    三数之和
  3. 思路:
    <1> 将整个数组排序,固定一个数num,创建两个指针left(最左则)与right(固定数num的前一个元素)
    <2> 左右指针开始遍历数组,arr[left] + arr[right] < num,left指针右移,arr[left] + arr[right] > num,right指针左移,当arr[left] + arr[right] > num时,记录此次搭配。重复遍历步骤,直至left >= right,结束此次遍历
    <3> 重复步骤2,直至num < 2

过程演示:
在这里插入图片描述

class Solution 
{
public:
    vector<vector<int>> threeSum(vector<int>& nums)
    {
        //排序
        //去重
        //单调性
        vector<vector<int>> v1;

        sort(nums.begin(), nums.begin() + nums.size());
        
        int cur = nums.size() - 1;
        int right = 0;
        int left = 0;
        
        while (cur > 1)
        {
            right = cur - 1;
            left = 0;
            //一次遍历
            while (right > left)
            {
            	//判断同时去重
                if ((right < cur - 1 && nums[right] == nums[right + 1]) || nums[right] + nums[left] > -nums[cur])
                {
                    right--;
                }
                else if ((left > 0 && nums[left] == nums[left - 1]) || nums[right] + nums[left] < -nums[cur])
                {
                    left++;
                }
                else
                {
                	//记录
                    vector<int> v2;
                    v2.push_back(nums[left]);
                    v2.push_back(nums[right]);
                    v2.push_back(nums[cur]);
                    v1.push_back(v2);
                    right--;
                }
            }

            //去重
            do
            {
                cur--;
            } while (cur > 1 && nums[cur] == nums[cur + 1]);
        }

        return v1;
    }
};

1.8 四数之和

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    四数之和
  3. 思路:在三指针的基础上再套一层
  4. 注:int类型存在数据溢出的风险
class Solution
{
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target)
    {
        sort(nums.begin(), nums.end());

        vector<vector<int>> vv;

        int end = nums.size() - 1;
        int a = 0;
        while (end - a + 1 >= 4)
        {
            int b = a + 1;
            while (end - b + 1 >= 3)
            {
                int left = b + 1;
                int right = end;
                while (left < right)
                {
                    int sum = nums[left] + nums[right];
                    long long goal = (long long)target - nums[a] - nums[b];
                    //去重
                    if ((right < end && nums[right + 1] == nums[right]) || sum > goal)
                    {
                        right--;
                    }
                    else if ((left > b + 1 && nums[left - 1] == nums[left]) || sum < goal)
                    {
                        left++;
                    }
                    else
                    {
                        vector<int> v;
                        v.push_back(nums[a]);
                        v.push_back(nums[b]);
                        v.push_back(nums[left]);
                        v.push_back(nums[right]);

                        vv.push_back(v);
                        
                        left++;
                    }
                }
                do
                {
                    b++;
                } while (end - b + 1 >= 3 && nums[b - 1] == nums[b]);
            }
            do
            {
                a++;
            } while (end - a + 1 >= 4 && nums[a - 1] == nums[a]);
        }

        return vv;
    }
};

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

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

相关文章

线程有几种状态,状态之间的流转是怎样的?

Java中线程的状态分为6种&#xff1a; 1.初始(NEW)&#xff1a;新创建了一个线程对象&#xff0c;但还没有调用start()方法。 2.运行(RUNNABLE)&#xff1a;Java线程中将就绪&#xff08;READY&#xff09;和运行中&#xff08;RUNNING&#xff09;两种状态笼统的称为“运行”…

红黑树的学习

红黑树 红黑树出自一种平衡的二叉查找树&#xff0c;是计算机科学中中用到的一种数据结构 1972年出现&#xff0c;当时被称之为平衡二叉B树。后来&#xff0c;1978年被修改为如今的红黑树 他是一种特殊的二叉查找树&#xff0c;红黑树的每一个节点上都有存储表示节点的颜色 …

WordPress建站入门教程:如何创建菜单和设置前端导航菜单?

前面我们跟大家分享了WordPress如何上传安装WordPress主题&#xff0c;但是启用主题后前端没有看到有导航菜单&#xff0c;这是因为我们还没有创建菜单和设置导航菜单。 JianYue主题导航菜单和右上角菜单 今天boke112百科就继续跟大家分享WordPress站点如何创建菜单和设置前端…

使用 Amazon Bedrock 上的 Claude 3 将架构图转换为 CDK/Terraform 代码

概述 在云原生领域&#xff0c;基础设施即代码 (IaC) 对于开发人员和 DevOps 团队来说是一种不可避免的实践。 最近&#xff0c;Amazon Bedrock 上线了 Claude 3 Sonnet 模型和这个模型的图像转文本能力。这无疑开启了一个新时代&#xff0c;也就是实现架构图与 IaC 工具的无…

【C++】C++11---右值引用和移动语义

目录 1、什么是左值引用和右值引用2、左值引用与右值引用比较3、右值引用使用场景和意义4、右值引用引用左值的分析5、完美转发 1、什么是左值引用和右值引用 传统的C语法中就有引用的语法&#xff0c;而C11中新增了的右值引用语法特性&#xff0c;所以从现在开始我们之前学习…

java-ssm-jsp-大学生评优管理系统的设计与实现

java-ssm-jsp-大学生评优管理系统的设计与实现 获取源码——》公主号&#xff1a;计算机专业毕设大全

kafka报文模拟工具的使用

日常项目中经常会碰到消费kafka某个topic的数据&#xff0c;如果知道报文格式&#xff0c;即可使用工具去模拟发送报文&#xff0c;以此测试代码中是否能正常消费到这个数据。 工具资源已上传&#xff0c;可直接访问连接下载&#xff1a;https://download.csdn.net/download/w…

C++ 标准库类型string

C/C总述&#xff1a;Study C/C-CSDN博客 目录 定义和初始化string对象 string的增 使用push_back进行尾插 使用insert插入 使用append函数完成string的拼接 string的删 使用pop_back进行尾删 使用erase删除 string的查 使用find函数正向搜索第一个匹配项 使用rf…

【MATLAB源码-第159期】基于matlab的胡桃夹子优化算法(NOA)机器人栅格路径规划,输出做短路径图和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 胡桃夹子优化算法&#xff08;Nutcracker Optimization Algorithm, NOA&#xff09;是一个灵感来源于胡桃夹子的故事的元启发式优化算法。这个故事中&#xff0c;胡桃夹子是一个能够将坚果壳轻易地破开以获取内部果仁的工具。…

腾讯云99元服务器有什么猫腻?为什么这么便宜?

腾讯云服务器99元一年是真的吗&#xff1f;真的&#xff0c;99元优惠购买入口 txybk.com/go/99 折合每天8元1个月&#xff0c;腾讯云99元服务器配置为2核2G3M带宽&#xff0c;2024年99元服务器配置最新报价为61元一年&#xff0c;为什么这么便宜&#xff1f;有什么猫腻吗&#…

【工具】Raycast – Mac提效工具

引入 以前看到同事们锁屏的时候&#xff0c;不知按了什么键&#xff0c;直接调出这个框&#xff0c;然后输入lock屏幕就锁了。 跟我习惯的按Mac开机键不大一样。个人觉得还是蛮炫酷的&#xff5e; 调研 但是由于之前比较繁忙&#xff0c;这件事其实都忘的差不多了&#xff0…

网工内推 | 网络工程师,IE认证优先,最高15K,有项目绩效奖金

01 重庆并联网络科技有限公司 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、负责集成项目的相关实施工作&#xff08;设备上架安装、网络设备配置、服务器相关系统配置安装、相关软件环境搭建及配置等&#xff09; 2、负责项目现场技术维护与技术支持&#xff1b;…

蓝桥杯day6队列-3.3

目录 1.约瑟夫环 1.注意&#xff01;q.push(q.front()); 2.机器翻译 3.小桥的神秘礼盒 4.餐厅排队 1.约瑟夫环 今天学习了队列的STL写法&#xff0c;来试试这个题。 #include<bits/stdc.h> using namespace std;int main() {int n,m;cin>>n>>m;queue&l…

使用docker安装运行rabbitmq---阿里云服务器

目录 0、阿里云没开端口的得要去安全组规则去添加&#xff1a; 1、下载RabbitMQ镜像&#xff1a; 2、查看镜像是否下载成功&#xff0c;得到docker镜像id&#xff1a; 3、运行RabbitMQ: 4、查看RabbbitMQ容器是否启动成功&#xff1a; 5、启动RabbitMQ中的插件管理 6、访…

postman环境变量全局变量设置

postman环境变量、全局变量设置 在公司中&#xff0c;一般会存在开发环境、测试环境、线上环境等&#xff0c;如果需要在不 同的环境下切换做接口测试&#xff0c;显然我们需要把所有接口的域名进行修改&#xff0c;如果接 口测试用例较多&#xff0c;那么修改会非常费力&…

three.js 射线Ray,三维空间中绘制线框

效果&#xff1a; 代码&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs"></div> <div>{{ res1 }}</div> <div>{{ res2 }}</div><…

vue3的开发小技巧

「总之岁月漫长&#xff0c;然而值得等待。」 目录 父组件调用子组件函数如何访问全局api 父组件调用子组件函数 ref, defineExpose //父组件 代码 <child ref"ch">this.$refs.ch.fn();//子组件 函数抛出 const fn () > { }; defineExpose({ fn });如何…

influxdb2.0插入数据字段类型出现冲突问题解决

一、问题出现 一个学校换热站自控系统&#xff0c;会定时从换热站获取测点数据&#xff0c;并插入到influxdb数据库中。influxdb插入数据时&#xff0c;报错提示&#xff1a; com.influxdb.exceptions.UnprocessableEntityException: failure writing points to database: par…

目标检测——摩托车头盔检测数据集

一、简介 首先&#xff0c;摩托车作为一种交通工具&#xff0c;具有高速、开放和稳定性差的特点&#xff0c;其事故发生率高&#xff0c;伤亡率排在机动车辆损伤的首位。因此&#xff0c;摩托车乘员头盔对于保护驾乘人员头部安全至关重要。在驾乘突发状况、人体受冲击时&#…

白话模电:1.绪论与半导体(考研面试常问问题)

一、什么是信号&#xff1f;什么是电信号&#xff1f; 信号反映消息的物理量&#xff0c;电信号是反应电压或电流变化的物理量。 二、什么是模拟信号&#xff1f;什么是数字信号&#xff1f; 模拟信号是时间和数值上均连续的信号&#xff0c;数字信号是时间和数值上均离散的信号…