双指针系列:移动零,多解法拓宽你的思路

在这里插入图片描述

Leetcode 题目链接

前言

本篇统一采用如下数组,并且采用双指针。蓝色指针为 l l l,橙色指针为 r r r。初始 l , r l,r l,r 的 index 均为 0。

283_2.png
代码均为 Java。

解法一

记元素向左的偏移量为 offset,初始 offset = 0。

每次发现元素为 0 时增加偏移量,发现元素非 0 且偏移量非 0 时偏移元素。

class Solution {
    public void moveZeroes(int[] nums) {
        int offset = 0;

        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == 0) {
                offset++;
            } else if (offset != 0) {
                nums[i - offset] = nums[i];
                nums[i] = 0;
            }
        }
    }
}

解法二

如下所示,我们可以将 l l l 移动到自身右侧第一个元素为 0 的位置,将 r r r 移动到 l l l 右侧第一个元素非 0 的位置,然后交换元素。283_3.png
然后再执行上一步骤,循环下去,直至 r r r 抵达边界。

class Solution {
    public void moveZeroes(int[] nums) {
        int l = 0;
        int r = 0;

        while (r < nums.length) {
            if (r == l || nums[r] == 0) {
                r++; // 优先检测 r,确保 r 在 l 右侧
            } else if (nums[l] != 0) {
                l++;
            } else {
                nums[l] = nums[r];
                nums[r] = 0;
            }
        }
    }
}

解法三

出发点是记录第一个元素为 0 的位置,并在每次交换元素时更新。

class Solution {
    public void moveZeroes(int[] nums) {
        int l = 0;

        for (int r = 0; r < nums.length; r++) {
            if (nums[r] == 0) continue;
            int temp = nums[l];
            nums[l] = nums[r];
            nums[r] = temp;
            l++;
        }
    }
}

取示例数组如下所示,分析代码的运行过程。
初始时 N u m s [ l ] = N u m s [ r ] ≠ 0 Nums[l] = Nums[r] \neq 0 Nums[l]=Nums[r]=0,交换不产生影响。 l , r l, r l,r 同步前进。

283_2.png

如下所示,在发现元素 0 时, l l l 保持不变, r r r 前进至 N u m s [ r ] ≠ 0 Nums[r] \neq 0 Nums[r]=0

283_4.png

再如下所示,交换元素, l l l 前进。
283_5.png

此后 r r r 前进,一直寻找非 0 元素与 l l l 处的 0 交换即可。

复杂度

以上解法复杂度一致。

时间: Θ ( n ) \Theta(n) Θ(n)
空间: Θ ( 1 ) \Theta(1) Θ(1)

推广

这里有附个人题解的双指针题单

笔者著有 Leetbooks 《图论入门》《图论进阶》,且在陆续写其他 Leetbooks。致力于提升广大读者真正的算法水平,并兼顾不同阶段的读者,如本科阶段、硕士阶段、职场面试、算法竞赛。

  • 19
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值