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

算法学习:

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--;
        }
    }
};
相关推荐
NAGNIP4 小时前
万字长文!回归模型最全讲解!
算法·面试
知乎的哥廷根数学学派4 小时前
面向可信机械故障诊断的自适应置信度惩罚深度校准算法(Pytorch)
人工智能·pytorch·python·深度学习·算法·机器学习·矩阵
qq_318121594 小时前
互联网大厂Java面试故事:从Spring Boot到微服务架构的技术挑战与解答
java·spring boot·redis·spring cloud·微服务·面试·内容社区
txinyu的博客4 小时前
解析业务层的key冲突问题
开发语言·c++·分布式
666HZ6665 小时前
数据结构2.0 线性表
c语言·数据结构·算法
SmartRadio5 小时前
ESP32添加修改蓝牙名称和获取蓝牙连接状态的AT命令-完整UART BLE服务功能后的完整`main.c`代码
c语言·开发语言·c++·esp32·ble
且去填词6 小时前
Go 语言的“反叛”——为什么少即是多?
开发语言·后端·面试·go
实心儿儿6 小时前
Linux —— 基础开发工具5
linux·运维·算法
charlie1145141917 小时前
嵌入式的现代C++教程——constexpr与设计技巧
开发语言·c++·笔记·单片机·学习·算法·嵌入式
清木铎8 小时前
leetcode_day4_筑基期_《绝境求生》
算法