力扣hot100:移动零问题的巧妙解决:双指针与原地交换策略(283)
在解决LeetCode上的移动零问题时(题目编号283),我们需要在不复制数组的情况下,将所有0移动到数组末尾,同时保持非零元素的相对顺序。今天我实现了一种高效解法,下面分享我的思路和代码。
问题描述
解法思路:双指针交换法
核心思路是使用快慢双指针:
- 快指针
fast
:遍历整个数组,寻找非零元素 - 慢指针
slow
:标记下一个非零元素应该放置的位置
当 fast
遇到非零元素时,将其与 slow
位置元素交换,然后 slow
向前移动。这样保证了:
- 所有非零元素被按顺序移到数组前部
- 所有0被交换到数组后部
- 非零元素的原始相对顺序保持不变
代码实现
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时直接返回(无操作必要)
- 单独处理长度为2的情况虽可省略,但体现了对边界条件的思考
双指针工作流程:
- 初始化:
slow = 0
,fast = 0
- 遍历中:
- 遇到非零 → 交换
slow
和fast
的值 →slow++
- 遇到零 → 仅
fast++
- 遇到非零 → 交换
- 结束:
fast
遍历完数组
- 初始化:
操作可视化:
初始: [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),仅用常数级额外空间
总结
通过快慢双指针的配合,我们实现了:
- 一次遍历完成操作
- 保持非零元素原始顺序
- 原地操作,无额外空间开销
这种解法体现了双指针在数组重排问题中的高效性。实际开发中,类似的思路也可用于其他元素分类问题,如将奇数偶数分离、特定值筛选等。
关键学习点:当需要保持元素原始顺序时,交换+双指针往往是比删除/新增更优的解决方案。