力扣hot100:移动零问题的巧妙解决:双指针与原地交换策略(283)

在解决LeetCode上的移动零问题时(题目编号283),我们需要在不复制数组的情况下,将所有0移动到数组末尾,同时保持非零元素的相对顺序。今天我实现了一种高效解法,下面分享我的思路和代码。

问题描述

解法思路:双指针交换法

核心思路是使用快慢双指针

  • 快指针 fast:遍历整个数组,寻找非零元素
  • 慢指针 slow:标记下一个非零元素应该放置的位置

fast 遇到非零元素时,将其与 slow 位置元素交换,然后 slow 向前移动。这样保证了:

  1. 所有非零元素被按顺序移到数组前部
  2. 所有0被交换到数组后部
  3. 非零元素的原始相对顺序保持不变

代码实现

java 复制代码
class Solution {
    public void moveZeroes(int[] nums) {
        int length = nums.length;
        if(length==0){
            return;
        }
        if(length==2){
            if(nums[0]==0&&nums[1]!=0){
                swap(nums,0,1);
            }else{
                return;
            }
        }

for(int slow=0,fast=slow;fast<length;){

            if(nums[fast]!=0){
                swap(nums,slow,fast);
                slow++;
            }
            
            fast++;
        }

    }

    public void swap(int[] nums,int slow,int fast){
        int temp=nums[fast];
        nums[fast]=nums[slow];
        nums[slow]=temp;
    }
    
}

关键点解析

  1. 边界处理优化

    • 长度≤1时直接返回(无操作必要)
    • 单独处理长度为2的情况虽可省略,但体现了对边界条件的思考
  2. 双指针工作流程

    • 初始化:slow = 0, fast = 0
    • 遍历中:
      • 遇到非零 → 交换 slowfast 的值 → slow++
      • 遇到零 → 仅 fast++
    • 结束:fast 遍历完数组
  3. 操作可视化

复制代码
初始: [0,1,0,3,12] 
步骤1: [0,1,0,3,12] // fast在1(非零),与slow(0)交换 
步骤2: [1,0,0,3,12] // slow=1, fast继续 
步骤3: [1,0,0,3,12] // fast遇到0,跳过 
步骤4: [1,3,0,0,12] // fast在3(非零),与slow(1)交换 
步骤5: [1,3,12,0,0] // fast在12(非零),与slow(2)交换

复杂度分析

  • 时间复杂度:O(n),仅遍历数组一次
  • 空间复杂度:O(1),仅用常数级额外空间

总结

通过快慢双指针的配合,我们实现了:

  • 一次遍历完成操作
  • 保持非零元素原始顺序
  • 原地操作,无额外空间开销

这种解法体现了双指针在数组重排问题中的高效性。实际开发中,类似的思路也可用于其他元素分类问题,如将奇数偶数分离、特定值筛选等。

关键学习点:当需要保持元素原始顺序时,交换+双指针往往是比删除/新增更优的解决方案。