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

算法学习:

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--;
        }
    }
};
相关推荐
wow_DG12 分钟前
【C++✨】多种 C++ 解法固定宽度右对齐输出(每个数占 8 列)
开发语言·c++·算法
小高00720 分钟前
🔥🔥🔥前端性能优化实战手册:从网络到运行时,一套可复制落地的清单
前端·javascript·面试
Epiphany.55622 分钟前
c++最长上升子序列长度
c++·算法·图论
Cx330❀1 小时前
【数据结构初阶】--排序(四):归并排序
c语言·开发语言·数据结构·算法·排序算法
绝无仅有1 小时前
编写 Go 项目的 Dockerfile 文件及生成 Docker 镜像
后端·面试·github
绝无仅有1 小时前
使用 Docker 部署 Go 项目(Beego 框架)
后端·面试·github
余_弦1 小时前
区块链中的密码学 —— 密钥派生算法
算法·区块链
亲爱的非洲野猪2 小时前
令牌桶(Token Bucket)和漏桶(Leaky Bucket)细节对比
网络·算法·限流·服务
颖川守一2 小时前
C++c6-类和对象-封装-设计案例2-点和圆的关系
开发语言·c++
luckyCover2 小时前
面试前来了解下TCP/IP网络模型吧~
前端·面试