算法每日双题精讲——双指针(移动零,复写零)

🌟快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。 🌟
别再犹豫了!快来订阅我们的算法每日双题精讲专栏,一起踏上算法学习的精彩之旅吧!💪


**💯**前言

**在算法的世界里,双指针技巧常常能发挥出神奇的作用😎。**今天,我们就来精讲两道利用双指针解决的经典题目:移动零和复写零。

📣由于俩道题目均为数组,这里的双指针算法指的是:利用数组下标代替指针

当我们遇到,数组分块,数组划分的问题时,可以考虑使用双指针法。


**💯**双指针的作用

✍两个指针的作用:

  • cur:从左往右扫描数组,遍历数组
  • dest:已处理的区间内,非零元素的最后一个位置

分为三个区间:

  1. 0, dest
  2. dest + 1,cur -1
  3. cur, n -1

💯移动零

题目链接👉【力扣】

题目描述:给定一个数组nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入:nums = {0,1,0,3,12}

输出:{1,3,12,0,0}

⭐解题思路:

我们可以使用双指针法来解决这个问题。一个指针cur用于遍历整个数组,另一个指针dest 用于指向当前非零元素应该放置的位置。当遇到非零元素时,将其放置在dest指针所指的位置,并将dest指针向后移动一位。遍历结束后,从dest指针开始到数组末尾的位置全部设置为零。

😀俩个指针将数组分为三个区间:

  1. 0, dest:全是非0的元素(已经处理)
  2. dest + 1,cur -1:都是0(已经处理)
  3. cur, n -1:还未处理过的
代码实现(以 C++ 为例):
cpp 复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        // dest 用于标记已处理的非零元素的最后位置
        int dest = -1;
        // cur 用于遍历整个向量
        int cur = 0;
        while (cur < nums.size()) {
            // 如果当前位置的元素为 0
            if (nums[cur] == 0) {
                cur++;
            } else {
                // 先将 dest 加 1,标记下一个非零元素应放置的位置
                swap(nums[++dest], nums[cur]);
                cur++;
            }
        }
    }
};
👀复杂度分析:
  • 时间复杂度:,其中 n 是数组的长度。我们只需要遍历一次数组。
  • 空间复杂度:,只使用了有限的额外空间。

💯复写零

题目链接👉【力扣】

题目描述:给你一个长度固定的整数数组arr,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。注意❗:不要在超过该数组长度的位置写入元素。

示例:

输入:arr = {1,0,2,3,0,4,5,0}

输出:{1,0,0,2,3,0,0,4}

解题思路:

同样可以使用双指针法来解决这个问题。一个指针cur用于遍历数组,另一个指针dest用于指向复写零后数组中元素应该放置的位置。当遇到零元素时,将dest指针后的元素依次向后移动两位,并在dest和 dest+1 的位置都放置零。当遇到非零元素时,将其放置在dest指针所指的位置,并将dest指针向后移动一位。

🙋这个解题思路是怎么来的呢?
  1. 首先我们从左往右遍历数组,

    当arrcur!=0时,我们让dest的后面一个的值赋予acur正指向的那个值

    当arrcur==0时,我们让dest的后俩个值都赋予0

    当走到这一步时:

    cur找不到下一个为2的值了,因此我们不能从左往右遍

  2. 我们从右往左遍历,dset指向最后一个元素,cur指向最后一个要复写的数
    当acur!=0时,让adest=acur,然后cur--,dest--;
    当acur==0时,让adest--=0,adest--=0,cur--;
    这样遍历没有问题,因此我们选择从右往左遍历
    所以我们只要找到最后要"复写"的数即可

⭐找最后一个要复写的数

👇起初让cur指向数组的开头,dest指向-1的位置:

代码实现(以 C++ 为例):
cpp 复制代码
class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        // dest 用于标记复制零元素后的新位置,初始值为 -1
        int dest = -1;
        // cur 用于遍历原始数组,初始值为 0
        int cur = 0;
        int n = arr.size();
        // 遍历原始数组,确定复制零元素后的新位置
        while (cur < n) {
            // 如果当前元素不为 0
            if (arr[cur]!= 0) {
                // dest 向后移动一位
                dest++;
            } else {
                // 如果当前元素为 0,dest 向后移动两位(因为要复制一个零)
                dest += 2;
            }
            // 如果 dest 已经到达或超过新数组的最后一个位置,跳出循环
            if (dest >= n - 1) break;
            // cur 向后移动一位,继续遍历原始数组
            cur++;
        }
        // 如果 dest 正好等于新数组的长度
        if (dest == n) {
            // 将新数组的最后一个位置设为 0
            arr[n - 1] = 0;
            // dest 回退两位
            dest -= 2;
            // cur 回退一位,因为上一步 cur 多走了一步
            cur--;
        }
        // 从后往前遍历原始数组,进行复制操作
        while (cur >= 0) {
            // 如果当前元素不为 0
            if (arr[cur]!= 0) {
                // 将当前元素复制到新位置
                arr[dest] = arr[cur];
                // cur 和 dest 都向前移动一位
                cur--;
                dest--;
            } else {
                // 如果当前元素为 0,先将 0 复制到 dest 位置,再将另一个 0 复制到 dest - 1 位置
                arr[dest--] = 0;
                arr[dest--] = 0;
                // cur 向前移动一位
                cur--;
            }
        }
    }
};
👀复杂度分析:
  • 时间复杂度:,其中 n 是数组的长度。我们需要遍历两次数组。
  • 空间复杂度:,只使用了有限的额外空间。

**💯**总结

通过这两道题目,我们可以看到双指针算法在处理数组相关问题时的高效性和灵活性👏。希望大家在今后的算法学习中,能够熟练掌握双指针技巧,解决更多复杂的问题💪。


我以后还会对 算法 相关知识进行更多的创作,欢迎大家关注我,一起探索 **算法的奇妙世界 😜

👉【A Charmer】

相关推荐
来自于狂人几秒前
第5章 记忆管理——让Agent记住事情
人工智能·算法·语言模型·自然语言处理
CHHH_HHH4 分钟前
【C++】哈希表原理与实战:从冲突解决到性能优化
开发语言·数据结构·c++·学习·算法·哈希算法·散列表
Cloud_Shy6184 分钟前
解读《Effective Python 3rd Edition》:从练气到老魔(第七章 Item 48 - 50)
开发语言·人工智能·笔记·python·microsoft·学习方法
sali-tec12 分钟前
C# 基于OpenCv的视觉工作流-章84-包胶有无检测
图像处理·人工智能·opencv·算法·计算机视觉
Irissgwe19 分钟前
数据结构-排序
数据结构·算法·排序算法
小O的算法实验室23 分钟前
2025年IEEE TITS,基于动态聚类粒子群算法的无人机任务分配与路径规划
算法
Tairitsu_H28 分钟前
[LC优选算法#5] 分治:快排 | 颜色分类 | 排序数组 | 第K大元素
c++·算法·leetcode·排序算法·快速排序
青山木30 分钟前
Hot 100 --- 滑动窗口最大值
java·数据结构·算法·leetcode·动态规划
青山木31 分钟前
Hot 100 --- 除自身以外数组的乘积
java·数据结构·算法
Frank学习路上34 分钟前
【C++】面试:STL容器与算法
c++·算法·面试