当前位置: 首页 > article >正文

【算法笔记】双指针算法深度剖析

【算法笔记】双指针算法深度剖析

🔥个人主页大白的编程日记

🔥专栏算法笔记


文章目录

  • 【算法笔记】双指针算法深度剖析
    • 前言
    • 一.移动零
      • 1.1题目
      • 1.2思路分析
      • 1.3代码实现
    • 二.复写零
      • 2.1题目
      • 2.2思路分析
      • 2.3代码实现
    • 三.快乐数
      • 3.1题目
      • 3.2思路分析
      • 3.3代码实现
    • 四.盛水最多的容器
      • 4.1题目
      • 4.2思路分析
      • 4.3正确性证明
      • 4.4代码实现
    • 五.有效三角形个数
      • 5.1题目
      • 5.2思路分析
      • 5.3代码实现
    • 六.两数之和
      • 6.1题目
      • 6.2思路分析
      • 6.3代码实现
    • 七.三数之和
      • 7.1题目
      • 7.2思路分析
      • 7.3代码实现
    • 八.算法总结
    • 后言

前言

哈喽,各位小伙伴大家好!今天给大家分享的是入门算法双指针。算法我们程序员必备的技能。话不多说,咱们进入正题!向大厂冲锋!

一.移动零

1.1题目

  • 题目:移动零

1.2思路分析

这里我们无非就是想让数组维持非0元素在前,0元素在后的区间状态。同时不改变非0元素的相对顺序。那我们可以用区间思想,借助双指针维护我们的区间状态。

1.3代码实现

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]);//dest移动后交换
            }
        }
    }
};
//分成三个区间未处理区
//处理区分区为非0元素区和0元素区

二.复写零

2.1题目

  • 题目:复写零

2.2思路分析

我们从左往右无法复写,因为会覆盖后面的数据。但是从右往左复写可以。所以我们找到最后一个复写的数,处理一下特殊情况从右往左复写即可。

2.3代码实现

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

三.快乐数

3.1题目

  • 题目:
    快乐数

3.2思路分析

这里我们根据鸽巢原理就可以把题目转化为判断入环点是否为1。
具体快慢指针相遇的问题可以看这篇 快慢指针相遇证明

3.3代码实现

这里我们用两个变量代替指针的作用。

class Solution {
public:
        int bitSum(int n)//计算每个数的平方和
        {
            int sum=0;
            while(n)
            {
                sum+=pow(n%10,2);
                n/=10;
            }
            return sum;
        }
        bool isHappy(int n) {
        int slow=bitSum(n);
        int fast=bitSum(slow);
        while(slow!=fast)
        {
            slow=bitSum(slow);
            fast=bitSum(fast);
            fast=bitSum(fast);
        }
        return slow==1;//判断入环点是否为1
    }
};

四.盛水最多的容器

4.1题目

  • 题目:盛水最多的容器

4.2思路分析

这里我们需要观察规律解题。

4.3正确性证明

4.4代码实现

class Solution {
public:
        int maxArea(vector<int>& height)
        {
            int max=0;
            int left=0,right=height.size()-1;
            while(left<right)//双指针法
            {
            int v=fmin(height[left],height[right])*(right-left);//保存枚举的最大值
            max=fmax(v,max);//更新最大值
            height[left]<height[right]?left++:right--;
        }
        return max;
    }
};

五.有效三角形个数

5.1题目

  • 题目:有效三角形的个数

5.2思路分析

这里我们用排序的单调性做优化.

正确性证明上一个题解有,这里就不过多赘述了。

5.3代码实现

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

六.两数之和

6.1题目

  • 题目:两数之和
    这里题目改了但是题意是一样的

6.2思路分析

这里依旧是按照单调性优化。

需要注意的是如果我们找到存在多个结果,我们找到结果后让left和right指针继续移动查找即可。

6.3代码实现

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) 
    {
        sort(nums.begin(),nums.end());//排序
        int left=0,right=nums.size()-1;
        while(left<right)
        {
            int tmp=nums[left]+nums[right];
            if(tmp<target)
            {
                left++;
            }
            else if(tmp>target)
            {
                right--;
            }
            else //找到结果
            {
                return {nums[left],nums[right]};
            }
        }
        return {};
    }
};

七.三数之和

7.1题目

  • 题目:三数之和

7.2思路分析

这里我们可以转化为两数之和来解决问题。但是要注意去重的问题。

7.3代码实现

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) 
    {
        vector<vector<int>> ret;
        sort(nums.begin(),nums.end());
        for(int i=0;i<nums.size()-2;)//固定最左边的指针
        {
            if(nums[i]>0)//大于没结果
            {
                break;
            }
            int left=i+1,right=nums.size()-1;
            int target=-nums[i];//找两数之和
            while(left<right)//左右指针两数之和,先移动再比较
            {
                int tmp=nums[left]+nums[right];
                if(tmp<target)//小于
                {
                    left++;
                    while(left<right&&nums[left]==nums[left-1])//跳过重复元素去重
                    {
                        left++;
                    }
                }
                else if(tmp>target)//大于
                {
                    right--;
                    while(left<right&&nums[right]==nums[right+1])//跳过重复元素去重
                    {
                        right--;
                    }
                }
                else//相等
                {
                    ret.push_back({nums[i],nums[left],nums[right]});//记录结果
                    left++;
                    right--;
                    while(left<right&&nums[left]==nums[left-1])//跳过重复元素去重
                    {
                        left++;
                    }
                    while(left<right&&nums[right]==nums[right+1])//跳过重复元素去重
                    {
                        right--;
                    }
                }
            }
            i++;
            while(i<nums.size()&&nums[i]==nums[i-1])//跳过重复元素去重
            {
                    i++;
            }
            //去重
        }
        return ret;
    }
};

八.算法总结

双指针算法总体来说就是利用两个指针,根据题目要求灵活结合单调性,区间思想,以及题目场景用指针的移动访问解决问题。总而言之,双指针需要根据题目灵活使用解决问题

后言

这就是双指针算法原理的深度剖析,这些题目基本包含了双指针的所有解题方法。大家自己好好消化。感谢大家的耐心垂阅!今天就分享到这,咱们下期见!拜拜~


http://www.kler.cn/news/340665.html

相关文章:

  • 喜马拉雅FM车机版 2.0 | 车载音频利器,免登录无广告
  • REINFORCEMENT LEARNING THROUGH ACTIVE INFERENCE
  • 【python 简易入门应用教程】第二部分:数据处理与分析
  • ROS2初级面试题总结
  • 每天一道面试题(8):垃圾收集器GC中的Humongous Regions是什么??
  • Coggle数据科学 | 全球AI攻防挑战赛:金融场景凭证篡改检测 baseline
  • 晶体管最佳效率区域随频率逆时针旋转原因分析
  • express 中环境变量配置
  • 手撕SwiGLU和GELU
  • 基于依赖注入技术的.net core WebApi框架创建实例
  • 前端开发中的高级技巧与最佳实践
  • 天气API接口调用
  • 【树形DP】AT_dp_p Independent Set 题解
  • yolov8/9/10/11模型在中医舌苔分类识别中的应用【代码+数据集+python环境+GUI系统】
  • 【2024】前端学习笔记11-网页布局-弹性布局flex
  • 【C++】输入输出缺省参数
  • k8s的pod管理及优化
  • linux线程 | 一篇文章带你理解线程的概念
  • STM32单片机(F03C8T6)-点灯(寄存器点灯和库函数点灯)
  • oracle查询表空间信息