(每日一题) 力扣 283 移动零

文章目录

      • [**一、问题分析** 💡](#一、问题分析 💡)
      • [**二、算法思路** 🚀](#二、算法思路 🚀)
      • [**三、分步图解(以示例 `nums = 0,1,0,3,12` 为例)** 📊](#三、分步图解(以示例 nums = [0,1,0,3,12] 为例) 📊)
        • [**1. 初始化指针**](#1. 初始化指针)
        • [**2. 第一次循环(`cur=0`)**](#2. 第一次循环(cur=0))
        • [**3. 第二次循环(`cur=1`)** 🎯](#3. 第二次循环(cur=1) 🎯)
        • [**4. 第三次循环(`cur=2`)**](#4. 第三次循环(cur=2))
        • [**5. 第四次循环(`cur=3`)** 🔄](#5. 第四次循环(cur=3) 🔄)
        • [**6. 第五次循环(`cur=4`)** ✨](#6. 第五次循环(cur=4) ✨)
      • [**四、代码解析** 🛠️](#四、代码解析 🛠️)
        • [**关键点解释** 📌](#关键点解释 📌)
      • [**五、总结** ✅](#五、总结 ✅)

一、问题分析 💡

题目要求将数组中的零元素全部移动到末尾,同时保持非零元素的原始顺序。关键约束是必须原地操作,即不能使用额外数组空间。这意味着我们需要在遍历过程中通过交换或覆盖元素实现目标。


二、算法思路 🚀

核心思想是使用双指针策略:

  1. 快指针 cur:从左到右遍历数组,寻找非零元素。
  2. 慢指针 dest:始终指向当前已处理好的非零序列的末尾下一个位置。

操作逻辑:

  • 当 nums[cur] 非零时,将其与 dest 位置交换,并让 dest 后移。
  • 最终,所有非零元素会被集中到数组前端,而 dest 之后的位置自然会被零填充。

三、分步图解(以示例 nums = [0,1,0,3,12] 为例) 📊

1. 初始化指针
  • dest = -1(表示尚未找到非零元素)

  • cur = 0(从数组头部开始遍历)

    初始状态:
    nums = [0, 1, 0, 3, 12]
    ↑
    cur=0, dest=-1

2. 第一次循环(cur=0)
  • nums[0] 是 0 → 不交换,cur 右移。

    状态不变:
    nums = [0, 1, 0, 3, 12]
    ↑
    cur=1, dest=-1

3. 第二次循环(cur=1) 🎯
  • nums[1] = 1 非零 → dest 先自增到 0,交换 nums[0] 和 nums[1]。

    交换后:
    nums = [1, 0, 0, 3, 12]
    ↑
    cur=1, dest=0

  • cur 右移,dest 更新为 0。

4. 第三次循环(cur=2)
  • nums[2] = 0 → 不交换,cur 右移。

    状态不变:
    nums = [1, 0, 0, 3, 12]
    ↑
    cur=3, dest=0

5. 第四次循环(cur=3) 🔄
  • nums[3] = 3 非零 → dest 自增到 1,交换 nums[1] 和 nums[3]。

    交换后:
    nums = [1, 3, 0, 0, 12]
    ↑
    cur=3, dest=1

  • cur 右移,dest 更新为 1。

6. 第五次循环(cur=4) ✨
  • nums[4] = 12 非零 → dest 自增到 2,交换 nums[2] 和 nums[4]。

    交换后:
    nums = [1, 3, 12, 0, 0]
    ↑
    cur=4, dest=2

  • 遍历结束,所有非零元素已按序排列在前,后续位置自动补零。


四、代码解析 🛠️

cpp 复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        for (int cur = 0, dest = -1; cur < nums.size(); ++cur) {
            if (nums[cur]) {  // 🎯 当前元素非零
                swap(nums[++dest], nums[cur]);  // 🔄 交换到非零序列末尾
            }
        }
    }
};
关键点解释 📌
  1. dest 的初始化:初始为 -1,表示尚未找到任何非零元素。
  2. 交换条件 :仅当 nums[cur] 非零时,将其交换到 dest 的下一个位置(即 ++dest)。
  3. 时间复杂度:O(n) 🚀,仅一次遍历。
  4. 空间复杂度:O(1) 💾,原地操作。

五、总结 ✅

双指针法是解决此类问题的经典策略,通过一次遍历实现高效操作。核心在于维护两个指针的语义:

  • dest 始终指向已处理的非零序列末尾。
  • cur 负责探索未处理区域,将非零元素按序交换到前方。
相关推荐
I_belong_to_jesus2 小时前
C++关于分支预测的优化1
开发语言·c++·算法
Rabitebla3 小时前
【Linux】进程控制(十二) 自定义 Shell(二):内建命令与进程工作目录管理
linux·c++·笔记·学习·bash
坤坤子吖7 小时前
Linux网络编程:TCP 粘包与半包问题,如何正确处理 TCP 流式数据?
linux·服务器·网络·笔记·网络协议·学习
AI_Gump7 小时前
Harness篇|DeepSeek Harness 上手机:五条安卓移植路线与 App 内 Linux 拆解
android·linux·人工智能·智能手机·deepseek
码客-ygluu9 小时前
一个通用游戏数据服务器
c++·架构
another heaven9 小时前
【C/C++ Ranges 是零开销抽象吗?拆开管道、惰性求值和编译期膨胀】
c语言·开发语言·c++
Code_Solitude9 小时前
C语言动态内存 + 柔性数组 + 数组名退化
c语言·算法·柔性数组
上海潭龙东海科技有限公司9 小时前
客运站管控之动态孪生技术方案(新增一屏管控模块
数据仓库·人工智能·算法·重构·动态规划
星恒随风9 小时前
MySQL 从零入门(六):复合查询详解——多表查询、自连接、子查询与 UNION
linux·服务器·数据库·mysql