双指针1:移动零

🔥个人主页: Milestone-里程碑

❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>

<<Git>><<MySQL>>

🌟心向往之行必能至

题目描述

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。注意:必须在不复制数组的情况下原地对数组进行操作。

示例

  • 输入:nums = [0,1,0,3,12]
  • 输出:[1,3,12,0,0]

方法一:双指针交换法

思路

我们可以用一个指针 left 来记录当前非零元素应该放置的位置,然后遍历数组。当遇到非零元素时,就将它与 left 位置的元素交换,并让 left 指针右移。这样可以保证 left 指针之前的所有元素都是非零的,且保持了原有顺序。

代码实现

cpp

复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int left = 0;
        for (auto& x : nums) {
            if (x != 0) {
                swap(x, nums[left]);
                left++;
            }
        }
    }
};

复杂度分析

  • 时间复杂度:O (n),其中 n 是数组的长度。我们只需要遍历一次数组。
  • 空间复杂度:O (1),只使用了常数级的额外空间。

方法二:覆盖补零法

思路

  1. 先遍历数组,把所有非零元素依次覆盖到数组的前面,用一个变量 stack_size 记录当前覆盖的位置。
  2. 遍历完成后,stack_size 及之后的位置全部补零即可。

代码实现

cpp

复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int stack_size = 0;
        // 第一步:把非零元素移到前面
        for (int x : nums) {
            if (x != 0) {
                nums[stack_size++] = x;
            }
        }
        // 第二步:后面的位置全部补零
        while (stack_size < nums.size()) {
            nums[stack_size++] = 0;
        }
    }
};

复杂度分析

  • 时间复杂度:O (n),两次遍历数组,总时间还是线性的。
  • 空间复杂度:O (1),同样是原地操作。

方法对比

方法 优点 缺点
双指针交换法 只需一次遍历,操作次数更少 交换操作会多写几次赋值
覆盖补零法 逻辑直观,容易理解 需要两次遍历,操作次数略多

在进阶要求 "尽量减少操作次数" 时,双指针交换法会更有优势。


总结

这道题的核心是原地修改保持相对顺序,两种方法都能满足要求。

相关推荐
亲爱的非洲野猪2 小时前
动态规划进阶:博弈DP深度解析
算法·动态规划
week_泽2 小时前
Git常用命令和SSH传输大文件的解决方案
大数据·elasticsearch·搜索引擎·github
甘露s2 小时前
Redis 核心:概念理解与五大数据结构
数据结构·数据库·redis
苦藤新鸡2 小时前
39.判断对称二叉树
数据结构·力扣
Dovis(誓平步青云)2 小时前
《优化算法效率的利器:双指针的原理、变种与边界处理》
linux·运维·算法·功能详解
多米Domi0112 小时前
0x3f 第41天 setnx的分布式锁和redission,白天写项目书,双指针
数据结构·分布式·python·算法·leetcode·缓存
智者知已应修善业2 小时前
【输入字符串不用数组回车检测转换连续数字为整数】2024-10-26
c语言·c++·经验分享·笔记·算法
JavaLearnerZGQ2 小时前
ElasticSearch 笔记1
大数据·笔记·elasticsearch
wdfk_prog2 小时前
Git文件状态显示异常的解决方案
大数据·git·elasticsearch