当前位置: 首页 > article >正文

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

文章目录

      • **一、问题分析** 💡
      • **二、算法思路** 🚀
      • **三、分步图解(以示例 `nums = [0,1,0,3,12]` 为例)** 📊
        • **1. 初始化指针**
        • **2. 第一次循环(`cur=0`)**
        • **3. 第二次循环(`cur=1`)** 🎯
        • **4. 第三次循环(`cur=2`)**
        • **5. 第四次循环(`cur=3`)** 🔄
        • **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
  • 遍历结束,所有非零元素已按序排列在前,后续位置自动补零。

四、代码解析 🛠️

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 负责探索未处理区域,将非零元素按序交换到前方。

http://www.kler.cn/a/578835.html

相关文章:

  • 强化学习(赵世钰版)-学习笔记(4.值迭代与策略迭代)
  • 跟着 Lua 5.1 官方参考文档学习 Lua (12)
  • 浅谈流媒体协议以及视频编解码
  • C#中异步窗体的调用方法
  • sqlserver中的锁模式 | SQL SERVER如何开启MVCC(使用row-versioning)【启用行版本控制减少锁争用】
  • 如何基于LLM及NL2SQL打造对话式智能BI助手
  • Go JSON数据处理(Gin+Gorm)
  • 摩托车PKE感应一键启动智能安全双防护
  • 2025/03/06(嵌入式学习开始第二天)
  • C++ Qt创建计时器
  • godot在_process()函数实现非阻塞延时触发逻辑
  • 基于模糊PID控制器的混合动力汽车EMS能量管理控制系统simulink建模与仿真
  • 深度学习PyTorch之13种模型精度评估公式及调用方法
  • 3.3.2 Proteus第一个仿真图
  • 基于DeepSeek与搜索引擎构建智能搜索摘要工具
  • ThinkPhp 5 安装阿里云内容安全(绿化)
  • STM32-I2C通信外设
  • 解决JDK 序列化导致的 Redis Key 非预期编码问题
  • npm install 报错ERESOLVE
  • Django工程获取请求参数的几种方式