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

算法学习:

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--;
        }
    }
};
相关推荐
23级二本计科2 分钟前
综合练习dfs_1
算法·leetcode·深度优先
L73S373 分钟前
栈和队列详解
数据结构·数据库·程序人生·算法·链表·学习方法
晚雾也有归处5 分钟前
结构体(C语言)
c语言·开发语言·数据结构·算法
qq_4335545415 分钟前
C++面向对象编程:纯虚函数、抽象类、虚析构、纯虚析构
开发语言·c++·算法
shadoubuhuijiji16 分钟前
C语言——指针和数组名含义的辨析
c语言·算法
Studying 开龙wu1 小时前
机器学习算法的分类
算法·机器学习·分类·回归
Chenglin_Yu2 小时前
PCA降维算法详细推导
算法
old_power4 小时前
Linux(Ubuntu24.04)安装Eigen3库
linux·c++·人工智能
Wils0nEdwards5 小时前
Leetcode 最大正方形
算法·leetcode·职场和发展
捕鲸叉7 小时前
C++并发编程之内存屏障
c++·并发编程