【1++的刷题系列】之双指针

news2024/12/23 15:08:53

👍作者主页:进击的1++
🤩 专栏链接:【1++的刷题系列】

文章目录

  • 一,什么是双指针
  • 二,相关例题
    • 例一
    • 例二
    • 例三
    • 例四
    • 例五

一,什么是双指针

常见的双指针有两种形式:一种是对撞指针(也称为左右指针);另一种是快慢指针。

对撞指针从两指针向中间移动,一个指针在最左端,一个在最右端,逐渐向中间移动。
其终止条件一般是两指针相遇或错开,或是得到结果,直接跳出内部循环。

快慢指针的基本原理就是两个速度不同的指针在数组或链表上移动。
这种方法处理环形链表或数组是非常有用的。不单单是环形链表或数组,处理循环往复的情况时我们都可以用快慢指针来解决。
最常用的一种快慢指针就是快指针走两步,慢指针走一步。

二,相关例题

例一

在这里插入图片描述

题解:
我们通过题目可以知道,这道题涉及到了数组内部元素的移动,因此我们想到用双指针的解法。
再仔细分析题目我们可以看到,题目中是要将0元素全部放在最后,并且非0 元素的相对位置不能改变,因此我们想到用快慢指针的方法来解决。
下面我们展示两种快慢指针的思路。

解法一:

lass Solution {
public:
    void moveZeroes(vector<int>& nums) 
    {
        //快慢指针
        if(nums.size()==1 || nums.empty())
            return ;

            int right=1;
            int left=0;
            while(right<nums.size()&&left<nums.size())
            {
                while(right<nums.size() && nums[right]==0)
                {
                    right++;
                }
                if(right>=nums.size())//对没有0时的处理
                    break;

                while(nums[left]!=0 && left<right)
                {
                    left++;
                }

                swap(nums[right],nums[left]);
                right++;

            }

    }
};

我们可以将数组分为三部分:非0区—0区–待处理区。
接着我们定义left,right指针。分别为一慢,一快。0-left是非0区;left-right是0区;right–结束 是待处理区。
通俗点就是left指针找0,right指针找非0 。然后两指针所指向内容进行交换。(要注意的是while循环条件的写法,防止数组越界)
最终该解法时间复杂度为O(n),空间复杂度为O(1)。

解法二:

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

    }
};

在这种解法中也是将数组划分为了上述的三个区域。left指向的是非0区的最后一个元素,而right则是向前找非0元素。然后与left的前一个元素(即0)进行交换。时间复杂度与空间复杂度与解法一相同,就是该方法更为简洁,不需要考虑特殊情况。

例二

在这里插入图片描述
本题也是对数组内部的元素进行移动,因此我们想到能够用双指针的写法来解决。
本题的暴力解法就是:再创建出一个数组,遍历原来的数组进行复写。但显然这种方法空间复杂度过高。
因此我们想如何能够在本数组内进行操作。若是从前往后我们用快慢指针来进行复写,则会将数组中原来的值遮盖。所以不行!因此我们考虑从后往前的可行性。我们发现后面的一些元素是再进行复写后将要被舍弃掉的。因此我们只需要找到需要复写后数组的最后一个元素,将复写要数组的最后一个元素移到数组最后。。。。这样就可以实现双指针了。

class Solution {
public:
    void duplicateZeros(vector<int>& arr) 
    {
      //找最后一个位置
      int right=-1;
      int cur=0;
      int n=arr.size();
      while(cur<n)
      {
          if(arr[cur]) right++;
          else
            right+=2;
        if(right>=n-1)
            break;
         
         cur++;

      }

      //调整
      if(right==n)
      {
          arr[n-1]=0;
          cur--;
          right-=2;
      }


      while(cur>=0)
      {
          if(arr[cur])
          {
              arr[right--]=arr[cur--];
          }
          else{
              arr[right--]=0;
              arr[right--]=0;
              cur--;
          }
      }


    }
};

本题中要注意的是两点:一是如何去找复写后最后一个元素;二是对于特殊情况的处理。
找最后一个元素我们通过模拟复写的过程的寻找,定义一个指向最后复写数的指针cur,模拟复写位置的指针right。则cur遇到0,right走两步,否则走一步,知道right超过数组大小。
对于特殊情况:出现这种情况的原因是,当复写的最后一个元素是0时,其可能由于数组已经到最后的原因不会写两次,但是我们在模拟找复写元素位置的时候却没有去考虑这种情况,因此此时的right会超过数组的大小。因此在中间步骤我们进行了纠正。

例三

在这里插入图片描述

我们分析题目,发现结果只有两种:变为1和无限循环但变不到1 。
对于循环的情况,我们就可以想到用快慢指针,一个追一个,若是在循环圈里快的追上慢的,则跳出,进行判断终止的数字是否为1 。

class Solution {
public:
 
    //求和
    long long bitsum(int n)
    {
        long long sum=0;
        while(n)
        {
            int x=n%10;
            sum+=x*x;
            n/=10;
        }
        return sum;
    }

    bool isHappy(int n) 
    {
        long long slow=n;
        long long fast=bitsum(n);
        while(slow!=fast)
        {
            slow=bitsum(slow);
            fast=bitsum(bitsum(fast));
        }

        if(slow==1)
        return true;
        else
        return false;
        
    }  

    
};

例四

在这里插入图片描述
在这里插入图片描述
我们来分析题目:
求容器的体积,无非就是求长,宽,高。这里宽是固定的,所以我们只需要考虑长和高。其高是有数组的长度决定的,高则是由数组两端的最小值决定的。
首先是暴力解法:
固定一端然后遍历一遍数组,直到所有情况被枚举出来。该方法时间复杂度为O(n^2),因此我们不采用。我们再进行观察:若是我们设数组的长依次降低,那么只有当其高度比现在的高度要高时,该体积才可能会增大。并且高由最短的一端决定,因此我们在数组的两端设两个指针,每次让指向最小值的那个指针进行遍历。我们就能够得出最大值了。

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

        return ret;

    }
};

例五

在这里插入图片描述
对于三角形来说,两条较短边的和若是大于第三边,则构成三角行。
若此题使用暴力解法,则需要从小到达列举所有的三元组,统计满足条件的三元组,这种方法的时间复杂度过高。达到了O(n^3) 。因此不可取。接下来我们进行优化。
**两条较短边的和若是大于第三边,则构成三角行。**涉及到最大的边的问题我们不妨将数组进行升序的排序。我们先固定一个最大的边,再在左右两端定义两个指向较短边的指针。若左右两端指针所指元素之和大于固定的第三遍,则这两个指针的区间内所有的元素均可以构成。再将右指针向左移,继续统计;若不大于,则做指针想右移。。。
直到固定的这个最大的边都匹配完,则指向最大的边的指针左移,继续上述操作。
这样我们的时间复杂度就降为了O(n^2) 。

class Solution {
public:
    int triangleNumber(vector<int>& nums) 
    {
        if(nums.size()<3) return 0;
        sort(nums.begin(),nums.end());
        //固定最大的一端
        int ret=0;
        for(int i=nums.size()-1;i>=2;i--)
        {
            int right=i-1;
            int left=0;
            while(right>left)
            {
                if(nums[left]+nums[right]>nums[i])
                {
                    ret+=right-left;
                    right--;
                }
                else
                {
                    left++;
                }
            }
        }

        return ret;
    }
};

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

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

相关文章

tinymce富文本编辑器【tip】

项目场景&#xff1a; tinymce富文本编辑器在iview的modal框中显示的问题 问题描述 最近在使用tinymceiviewvue写项目&#xff0c;在富文本编辑器配合弹框一起使用时&#xff0c;总是存在问题&#xff1a;弹框弹出的时候&#xff0c;富文本编辑器不能点击&#xff0c;鼠标的光…

【软考】PV 操作

#国庆发生的那些事儿# 临界资源: 诸进程间需要互斥方式对其进行共享的资源&#xff0c;如打印机、磁带机等临界区: 每个进程中访问临界资源的那段代码称为临界区信号量: 是一种特殊的变量。 信号量的值与相应资源的使用情况有关: ①: 当信号量的值大于0时&#xff0c;表示当…

Lucene学习总结之Lucene的索引文件格式

四、具体格式 上面曾经交代过&#xff0c;Lucene保存了从Index到Segment到Document到Field一直到Term的正向信息&#xff0c;也包括了从Term到Document映射的反向信息&#xff0c;还有其他一些Lucene特有的信息。下面对这三种信息一一介绍。 4.1. 正向信息 Index –> Seg…

Spring 体系架构模块和三大核心组件介绍

Spring架构图 模块介绍 1. Spring Core&#xff08;核心容器&#xff09;&#xff1a;提供了IOC,DI,Bean配置装载创建的核心实现。 spring-core &#xff1a;IOC和DI的基本实现 spring-beans&#xff1a;BeanFactory和Bean的装配管理(BeanFactory) spring-context&#xff1…

LLMs 用强化学习进行微调 RLHF: Fine-tuning with reinforcement learning

让我们把一切都整合在一起&#xff0c;看看您将如何在强化学习过程中使用奖励模型来更新LLM的权重&#xff0c;并生成与人对齐的模型。请记住&#xff0c;您希望从已经在您感兴趣的任务上表现良好的模型开始。您将努力使指导发现您的LLM对齐。首先&#xff0c;您将从提示数据集…

<C++> 模板-上

目录 前言 一、函数模板 1. 概念 2. 格式 3. 原理 4. 函数模板的实例化 4.1 隐式实例化 4.2 显示实例化 5. 模板参数的匹配原则 5.1 5.2 5.3 二、类模板 1. 类模板定义格式 2. 类模板的实例化 总结 前言 如何实现一个通用的函数&#xff0c;函数可以实现两个类型的交换&…

C++_pen_友元

友元&#xff08;破坏封装&#xff09; 我故意让别人能使用我的私有成员 友元类 friend class B;友元函数 friend void func();友元成员函数 friend void A::func();例 #include <stdio.h>class A;class C{ public:void CprintA(A &c); };class B{ public:void Bpri…

jira 浏览器插件在问题列表页快速编辑问题标题

jira-issueTable-quicker 这是一个可以帮助我们在问题表格页快速编辑问题的浏览器插件 github 地址 功能介绍 jira 不可否认是一个可以帮助有效提高工作效率的工具&#xff0c;但是我们在使用 jira 时使用问题表格可以让我们看到跟多的内容而不用关注细节&#xff0c;但是目…

c与c++中的字符串

在c中&#xff0c;string本质上是一个类&#xff1b; string与char *有些区别&#xff1a; char*是一个指针&#xff1b;string是一个类&#xff0c;类内封装了char*&#xff0c;管理这一个字符串&#xff0c;是一个char*的容器 在使用string类型时&#xff0c;要加上其头文…

用向量数据库Milvus Cloud 搭建AI聊天机器人

加入大语言模型(LLM) 接着,需要在聊天机器人中加入 LLM。这样,用户就可以和聊天机器人开展对话了。本示例中,我们将使用 OpenAI ChatGPT 背后的模型服务:GPT-3.5。 聊天记录 为了使 LLM 回答更准确,我们需要存储用户和机器人的聊天记录,并在查询时调用这些记录,可以用…

新版校园跑腿独立版小程序源码 多校版本,多模块,适合跑腿,外卖,表白,二手,快递等校园服务

最新校园跑腿小程序源码 多校版本&#xff0c;多模块&#xff0c;适合跑腿&#xff0c;外卖&#xff0c;表白&#xff0c;二手&#xff0c;快递等校园服务 此版本为独立版本&#xff0c;不需要** 直接放入就可以 需要自己准备好后台的服务器&#xff0c;已认证的小程序&#xf…

mysql面试题17:MySQL引擎InnoDB与MyISAM的区别

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:MySQL引擎InnoDB与MyISAM的区别 InnoDB和MyISAM是MySQL中两种常见的存储引擎,它们在功能和性能方面有一些区别。下面将详细介绍它们之间的差异。…

【微信小程序开发】一文学会使用CSS控制样式布局与美化

引言 在微信小程序开发中&#xff0c;CSS样式布局和美化是非常重要的一部分&#xff0c;它能够为小程序增添美感&#xff0c;提升用户体验。本文将介绍如何学习使用CSS进行样式布局和美化&#xff0c;同时给出代码示例&#xff0c;帮助开发者更好地掌握这一技巧。 一、CSS样式布…

基于HSV空间的彩色图像分割技术

1. 引言 每当我们看到图像时&#xff0c;它通常都是由各种元素和目标组成的。在某些情况下&#xff0c;我们可能会想要从图像中提取某个特定的对象&#xff0c;大家会怎么做&#xff1f;首先我们会想到的是进行crop相关的操作&#xff0c;这在某种程度上是可行的&#xff0c;但…

《数字图像处理-OpenCV/Python》连载(10)图像属性与数据类型

《数字图像处理-OpenCV/Python》连载&#xff08;10&#xff09;图像属性与数据类型 本书京东优惠购书链接&#xff1a;https://item.jd.com/14098452.html 本书CSDN独家连载专栏&#xff1a;https://blog.csdn.net/youcans/category_12418787.html 第2章 图像的数据格式 在P…

AcCode项目测试报告

文章目录 项目介绍编写测试用例根据测试用例编写自动化测试0.搭建测试环境1. 创建功能类2. 编写注册功能自动化3.编写登录功能自动化 性能测试1.使用VUG编写性能测试脚本2. 创建测试场景3.开始执行4. 简单分析性能测试报告事务报告运行的虚拟用户图表点击率表吞吐量图表系统资源…

C#,数值计算——Sobol拟随机序列的计算方法与源程序

1 文本格式 using System; using System.Collections.Generic; namespace Legalsoft.Truffer { /// <summary> /// Sobol quasi-random sequence /// </summary> public class Sobol { public Sobol() { } public static void sobseq(int n,…

堆排序——向下调整

之前我们要想实现堆排序&#xff0c;是运用建堆代码来实现的&#xff1a; 向上调整建堆——向下调整排序 那么去我们可不可以只适用一种调整方法&#xff08;向下调整&#xff09;就能实现这样的功能呢&#xff1f; 向要只使用向下调整就实现堆排序 首先就是把数组里的值使用…

互联网Java工程师面试题·Dubbo 篇·第二弹

目录 18、Dubbo 用到哪些设计模式&#xff1f; 19、Dubbo 配置文件是如何加载到 Spring 中的&#xff1f; 20、Dubbo SPI 和 Java SPI 区别&#xff1f; 21、Dubbo 支持分布式事务吗&#xff1f; 22、Dubbo 可以对结果进行缓存吗&#xff1f; 23、服务上线怎么兼容旧版本&…

设计模式12、代理模式 Proxy

解释说明&#xff1a;代理模式&#xff08;Proxy Pattern&#xff09;为其他对象提供了一种代理&#xff0c;以控制对这个对象的访问。在某些情况下&#xff0c;一个对象不适合或者不能直接引用另一个对象&#xff0c;而代理对象可以在客户端和目标对象之间起到中介的作用。 抽…