首页 > 编程语言 >算法专题一: 双指针

算法专题一: 双指针

时间:2024-09-08 13:49:25浏览次数:11  
标签:专题 cur nums int 算法 right 指针 left

目录

前言

常见的双指针有两种形式,一种是对撞指针,一种是左右指针。

1. 对撞指针: ⼀般用于顺序结构中,也称左右指针。

  • 对撞指针从两端向中间移动。⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼近。
  • 对撞指针的终止条件⼀般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循环),也就是:
    ◦ left == right (两个指针指向同⼀个位置)
    ◦ left > right (两个指针错开)

2. 快慢指针:又称为龟兔赛跑算法,其基本思想就是使用两个移动速度不同的指针在数组或链表等序列结构上移动。

这种方法对于处理环形链表或数组非常有用。

其实不单单是环形链表或者是数组,如果我们要研究的问题出现循环往复的情况时,均可考虑使用快慢指针的思想。

快慢指针的实现方式有很多种,最常用的⼀种就是:
• 在一次循环中,每次让慢的指针向后移动⼀位,而快的指针往后移动两位,实现一快一慢。

1. 移动零(easy)

题目链接:移动零

在这里插入图片描述
思想

在本题中,我们可以用一个 cur 指针来扫描整个数组,另一个 dest 指针用来记录非零数序列的最后一个位置。根据 cur 在扫描的过程中,遇到的不同情况,分类处理,实现数组的划分。

在这里插入图片描述

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

2. 复写零(easy)

题目链接: 复写零

在这里插入图片描述
算法思路

在这里插入图片描述

如果从前向后进行原地复写操作的话,由于0的出现会复写两次,导致没有复写的数被覆盖掉,因此我们选择从后往前的复写策略,但是从后往前复写的时候,我们需要找到最后一个复写的数,因此我们的大体流程分为两步:

  1. 先找到最后一个复写的数;
  2. 然后从后往前进行复写操作.
class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int cur = 0, dest = -1;

        while(cur < arr.size())
        {
            if(arr[cur])
                ++dest;
            else
                dest+=2;
            if(dest >= arr.size()-1)
                break;
            ++cur;
        }
        if(dest == arr.size())
        {
            dest--;
            arr[dest--] = 0;
            cur--;
        }
        while(cur>=0)
        {
            if(arr[cur])
            {
                arr[dest--] = arr[cur--];
            }else
            {
                arr[dest--] = 0;
                arr[dest--] = 0;
                cur--;
            }

        }

    }
};

3. 快乐数(medium)

题目链接: 快乐数

在这里插入图片描述
算法思路

根据分析我们可以知道, 当重复执行x的时候, 数据就会陷入到一个循环中, 而快慢指针有一个特性,就是在一个圆圈中, 快指针总是会追上慢指针的,也就是说他们会相遇在一个位置上, 如果相遇位置的值是1, 那么这个数一定是快乐数, 如果相遇的位置不是1的话, 那么这个数就不是快乐数.

在这里插入图片描述

class Solution {
public:
    int mutify(int n)
    {
        int ret =  0;
        while(n)
        {
            int ge = n % 10;
            ret += ge*ge;
            n/=10;
        }
        return ret;
    }
    bool isHappy(int n) {
        int fast = mutify(n), slow = n;
        while(fast != slow)
        {
            fast = mutify(mutify(fast));
            slow = mutify(slow);
        }
        return fast==1;
    }
};

4. 盛水最多的容器(medium)

题目链接: 盛水最多的容器

在这里插入图片描述

算法思路

设置两个指针left,right分别指向容器的左右两个端点,此时容器的容积v = (right - left) * min(hegiht[right] , height[left]). 容器的左边界为height[left], 右边界为height[right].如果此时我们固定一个边界, 改变另一个边界,水的容积会有如下变化形式:

  1. 容器的宽度一定变小.
  2. 由于左边界较小, 决定了水的高度,如果改变左边界,新的水面高度不确定,但是一定不会超过右边的柱子高度,因此容器的容积可能会增大.
  3. 如果改变右边界,无论右边界移动到哪里,新的水面的高度一定不会超过左边界,也就是不会超过现在的水面高度,但是由于容器的宽度减小,因此容器的容积一定会变小.

由此我们可以left++跳过,舍弃左边界和它的组合情况,继续下一个判断, 不断重复, 就可以舍去大量不必要的枚举过程,直到left和right相遇.

在这里插入图片描述

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

5. 有效三角形的个数(medium)

题目链接: 有效的三角形个数

在这里插入图片描述
算法思路

在这里插入图片描述

class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int ret = 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])
                {
                    left++;
                }
                else
                {
                    ret+=right - left;
                    right--;
                }
            }  
        }
        return ret;
    }
};

6. 和为 s 的两个数字(easy)

题目链接: 查找总价格为目标值的两个商品

在这里插入图片描述算法思路

在这里插入图片描述

class Solution {
public:
    vector<int> twoSum(vector<int>& price, int target) {
        int left = 0, right = price.size()-1;
        while(left < right)
        {
            if(price[left]+price[right] > target)
            {
                right--;
            }
            else if(price[left]+price[right]<target)
            {
                left++;
            }
            else
            {
                return {price[left],price[right]};
            }
        }
        return {-1,-1};
    }
};

7. 三数之和(medium)

题目链接: 三数之和

在这里插入图片描述
算法思路

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<vector<int>> vv;
       int n = nums.size();
       for(int i = 0; i<n;)
       {
            int target = -nums[i];
            int left = i+1,right = n-1;
            while(left<right)
            {
                int sum = nums[left]+nums[right];
                if(sum < target) left++;
                else if(sum > target) 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<n&&nums[i]==nums[i-1]) i++;
       }
       return vv; 
    }
};

8. 四数之和(medium)

题目链接: 四数之和

在这里插入图片描述

算法思路

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        vector<vector<int>> vv;
        int n = nums.size();
        for(int i = 0; i < n ;)
        {
            for(int j = i+1;j<n;)
            {
                long long a = (long long)target - nums[i] - nums[j];
                int left = j+1,right =n-1;
                while(left<right)
                {
                    int sum = nums[left] + nums[right];
                    if(sum<a) left++;
                    else if(sum>a) right--;
                    else
                    {
                        vv.push_back({nums[left],nums[right],nums[i],nums[j]});
                        left++,right--;
                        //去重1
                        while(left<right && nums[left] == nums[left-1]) left++;
                        while(left<right && nums[right] == nums[right+1]) right--;
                    }
                }
            j++;
            //去重2
            while(j<n && nums[j] == nums[j-1]) j++;
            }
        i++;
        while(i<n&&nums[i] == nums[i-1]) i++;    
        }
          return vv;
    }
  
};

标签:专题,cur,nums,int,算法,right,指针,left
From: https://blog.csdn.net/2201_75644377/article/details/141995330

相关文章

  • 信息学奥赛初赛天天练-86-NOIP2014普及组-基础题5-球盒问题、枚举算法、单源最短路、D
    1NOIP2014普及组基础题521把M个同样的球放到N个同样的袋子里,允许有的袋子空着不放,问共有多少种不同的放置方法?(用K表示)()例如,M=7,N=3时,K=8;在这里认为(5,1,1)和(1,5,1)是同一种放置方法。问:M=8,N=5时,K=()22如图所示,图中每条边上的数字表示该边的长度,则从......
  • 信息学奥赛初赛天天练-86-NOIP2014普及组-基础题5-球盒问题、枚举算法、单源最短路、D
    信息学奥赛初赛天天练-86-NOIP2014普及组-基础题5-球盒问题、枚举算法、单源最短路、Dijkstra算法、Bellman-Ford算法PDF文档公众号回复关键字:202409081NOIP2014普及组基础题521把M个同样的球放到N个同样的袋子里,允许有的袋子空着不放,问共有多少种不同的放置方法?(......
  • 算法入门-深度优先搜索2
    第六部分:深度优先搜索104.二叉树的最大深度(简单)题目:给定一个二叉树root,返回其最大深度。二叉树的最大深度是指从根节点到最远叶子节点的最长路径上的节点数。示例1:输入:root=[3,9,20,null,null,15,7]输出:3示例2:输入:root=[1,null,2]输出:2第一种思路:感觉递......
  • 【数据结构】单链表专题
    链表的概念及结构概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表的结构跟火车车厢相似,淡季时车次的车厢会相应减少,旺季时车次的车厢会额外增加几节。只需要将火车里的某节车厢去掉/加上,不会影响其他车......
  • 滑动窗口系列(背向双指针)9/8
    一、好子数组的最大分数给你一个整数数组 nums (下标从0开始)和一个整数 k 。一个子数组 (i,j) 的 分数 定义为 min(nums[i],nums[i+1],...,nums[j])*(j-i+1) 。一个 好 子数组的两个端点下标需要满足 i<=k<=j 。请你返回 好 子数组的最大可能......
  • 重生之霸道C语言爱上我之走入指针(4)
    这次重生的内容比较难,如果大家有很简单的理解方式,欢迎指正。经过前面三次的指针学习,我们已经知道了关于指针的基础知识和一些指针运用,现在我们继续进行更深入的指针运用学习。1.字符指针变量在前面的学习中,我们学习了一个指针类型为字符指针char*。一般使用:intmain(){ ......
  • 马老师浑元十三刀本质是DDD程序=算法+数据结构:浑元形意太极的本质是领域驱动设计(02)
    浑元形意太极的本质是领域驱动设计(01)在软件开发的旅程中,领域驱动设计就是我们的指路明灯。它照亮了我们前进的道路,驱散了迷茫的阴霾。有了领域驱动设计的指引,我们不再畏惧未知,不再害怕挑战。我们知道,无论前方有多么艰难的障碍,都有领域驱动设计为我们指明方向。领域驱动设计就......
  • 【电池专题】软包电池封装工序
    铝塑膜成型工序冲坑        铝塑膜成型工序,软包电芯可以根据客户的需求设计成不同的尺寸,当外形尺寸设计好后,就需要开具相应的模具,使铝塑膜成型。        成型工序也叫作冲坑,顾名思义,就是用成型模具在加热的情况下,在铝塑膜上冲出一个能够装卷芯的坑,具体的见......
  • 猎豹算法(CO)优化BP神经网络原理及Matlab代码
    目录0引言1数学模型2优化方式3Maltab代码3.1伪代码3.2CO主函数代码3.3CO-BP4视频讲解0引言猎豹算法(cheetahoptimizer,CO)是MohammadAminAkbari于2022年基于猎豹的狩猎策略启发而提出的智能算法。CO模拟猎豹的三种主要策略来捕猎猎物,即搜索、坐着和攻击;同时......
  • 猎豹算法(CO)优化支持向量机原理及Matlab代码
    目录0引言1数学模型2优化方式3Maltab代码3.1伪代码3.2CO主函数代码3.3CO-SVM4视频讲解0引言猎豹算法(cheetahoptimizer,CO)是MohammadAminAkbari于2022年基于猎豹的狩猎策略启发而提出的智能算法。CO模拟猎豹的三种主要策略来捕猎猎物,即搜索、坐着和攻击;同时......