【算法】——双指针(中)

算法学习:

https://blog.csdn.net/m0_73953114/category_12866812.html

前言

在上一节中,相信大家已经初步认识了双指针算法,那么在这一节中,将继续通过具体的题目操练的方式来帮助小伙伴们进一步对双指针的认识。

目录

1.移动零【力扣】

2.复写零


1.移动零【力扣】

题目解析:

对于这道题目,我们需要将系统所给的数组分成两部分左边为非零部分,右边为零部分 。对于非零部分中的元素,题目要求他们的相对顺序不能改变

图示如下:

算法原理:

在知道我们需要将数组分为两部分的时候,非零和零部分,那么我们想做的是不是就是遍历这个数组,一旦发现一个为0的元素,我们就将其与后面的第一个非零元素进行交换,直至将所有的零元素在非零元素的后面

图示如下:

​​​​​​

那么,我们该如何与双指针进行联系起来呢?

我们的目的是将该数组中的元素划分成非零部分和零部分,那么我们就可以设置两个指针,分别为cur和target。cur指针用来遍历这个数组发现非零元素 ,而target指针则来帮助我们进行非零元素和零元素的交换实现数组的分区

通过cur和target这个指针,其实我们在不断进行遍历这个数组的时候就将这个数组分成了三部分,cur将数组分为处理过的和待处理的,而target指针则将处理过的数组划分为非零元素和零元素。

【0,dest】,【dest+1,cur-1】,【cur,n-1】

非零元素 零元素 未处理

已处理

图示如下:

具体代码:

cpp 复制代码
class Solution1 {
public:
    void moveZeroes(vector<int>& nums) {
        int cur = 0, dest = -1;
        size_t n = nums.size();
        for (; cur < n; cur++)
        {
            if (nums[cur]) swap(nums[++dest], nums[cur]);
        }
    }
};

最后的动画演示效果:

2.复写零【力扣】

题目解析:

对于这道题目,当我们遍历这个数组的时候,一旦我们遇到非零元素,就要将其复写一次,也就是在这个零元元素与下一个元素之间插入一个零元素 ,要注意的一点就是一旦数组 给定,那么其大小是固定不变的。那么最后的0和5这两个元素就会被挤出这个数组

图示如下:

算法原理:

对于这道题目,我们可以首先考虑异地操作

对于异地操作来说就很简单,只需要再建立一个与原数组相同大小的数组,在遍历原数组的时候一旦我们遇到零元素就拷贝到新数组两次,而非零元素我们就只需要拷贝一次

但是题目要求的是同步操作 ,当我们仿照上面的异地操作进行的时候,就是非零元素不动,遇到零元素,就往后补一个零,但是这样子并不能得到我们想要的数组,会是这样的一个样子,这是由于我们在复写零的时候会将后面的有效元素进行覆盖,从而导致了其丢失

这时候我们会发现这是由于我们是从前往后写复写导致有效元素的覆盖,那么如果我们从数组的末尾往前来写的时候,是不是当我们进行复写零的时候,有效元素是依旧存在的。但是这解决了复写时有效元素被覆盖的问题 ,但是紧接着就是我们需要找到复写后数组的最后一个元素,这样我们才知道数组的末尾该从哪里进行复写?

因此本题的第一个步骤就是先找到最后一个"复写"的数然后就是进行复写的步骤 。那么依旧与上一题思路类似,我们通过两个指针cur和dest,cur指针从我们找到的最后一个"复写"的数开始往前遍历,而dest指针则根据cur的情况进行复写:1.cur指向零,复写两次 2.cur不指向0,复写一次 ,直至cur指针遍历到数组的开头为止

那么到此为止,有关算法思路的讲解就到此结束了,具体代码和图示如下:

cpp 复制代码
#复写零

class Solution6 {
public:
    void duplicateZeros(vector<int>& arr) {
        //找到复写后数组的最后一个元素
        int cur = 0,dest = -1;
        int sz = arr.size();
        for (; cur < arr.size(); cur++)
        {
            if (arr[cur] != 0) dest++;
            else dest += 2;
            //判断dest是否已经来到最后一个位置
            if (dest >= arr.size() - 1) break;
        }
        //开始进行复写
        // if(dest>sz-1) dest=sz-1;
        while (cur >= 0)
        {
            if (arr[cur] != 0)
            {
                if (dest > sz - 1) dest--;
                else arr[dest--] = arr[cur];
            }
            else {
                //避免dest越界写    
                if (dest > sz - 1) dest--;
                else arr[dest--] = arr[cur];
                arr[dest--] = arr[cur];
            }
            cur--;
        }
    }
};
相关推荐
王老师青少年编程几秒前
2024年信奥赛C++提高组csp-s初赛真题及答案解析(完善程序第2题)
c++·题解·真题·初赛·信奥赛·csp-s·提高组
夏鹏今天学习了吗2 分钟前
【LeetCode热题100(99/100)】柱状图中最大的矩形
算法·leetcode·职场和发展
Trouvaille ~4 分钟前
【Linux】进程间关系与守护进程详解:从进程组到作业控制到守护进程实现
linux·c++·操作系统·守护进程·作业·会话·进程组
千寻girling7 分钟前
《 MongoDB 教程 》—— 不可多得的 MongoDB
前端·后端·面试
啊阿狸不会拉杆8 分钟前
《机器学习导论》第 9 章-决策树
人工智能·python·算法·决策树·机器学习·数据挖掘·剪枝
Mr_Xuhhh9 分钟前
C++11实现线程池
开发语言·c++·算法
若水不如远方10 分钟前
分布式一致性(三):共识的黎明——Quorum 机制与 Basic Paxos
分布式·后端·算法
only-qi17 分钟前
leetcode24两两交换链表中的节点 快慢指针实现
数据结构·算法·链表
多恩Stone20 分钟前
【3D AICG 系列-9】Trellis2 推理流程图超详细介绍
人工智能·python·算法·3d·aigc·流程图
sin_hielo21 分钟前
leetcode 110
数据结构·算法·leetcode