[Java恶补day4] 283. 移动零

发布于:2025-05-24 ⋅ 阅读:(19) ⋅ 点赞:(0)

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序
请注意 ,必须在不复制数组的情况下原地对数组进行操作

示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:
输入: nums = [0]
输出: [0]

提示:
1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1

进阶:你能尽量减少完成的操作次数吗?


知识点:
数组、双指针


解:
采用双指针实现,初始时,左指针指向第一个元素,右指针指向第二个元素。
这里实际上已经考虑了一个元素的情况:只有一个元素时,不管是0还是非零元素,实际上不用动这个数组的内容,因此只考虑两个及以上元素数量的情况。
左指针,实际上指向的是0;右指针,实际上指向的是左指针指向的0后面第一个非零元素。
如何判断遍历结束了?通过判断右指针不等于数组长度,即可。原因在后面进行说明

这里对于指针指向的元素,分为3种情况:
case1:左指针指向0,右指针指向非零元素
这种情况下,需要交换左右指针指向的元素,实现非零元素向前移动、0向后移动。由于题目要求的是保证非零元素的相对顺序不变,而不同0的顺序实际上没区别,因此这种交换元素的方式是可取的。交换后,左指针就指向了非零元素,右指针指向了0,那么就来到了case3
case2:双指针均指向0
这种情况表示存在多个连续的0,那么交换0是没有实际意义的,为了减少交换次数,我们将右指针后移,直到后面的某次遍历时,右指针指向了非零元素,那么就来到了case1
case3:左指针指向非零元素
这种情况正是交换完0和非零元素后的结果,此时,左指针原来指向的0已经完成移动,标明左指针的使命已经完成,因此左指针后移。而双指针同时指向同一个元素,并没什么用,因此我们直接将右指针也后移。所以就有双指针同时后移

这里,以测试用例1进行说明,给出while循环的结束条件是如何确定的。
测试用例1推导过程
蓝色圈圈就说明了为什么右指针等于数组长度时,表明循环结束。

class Solution {
    public void moveZeroes(int[] nums) {
        //双指针分别指向第一个、第二个元素
        int pi = 0;
        int pj = 1;
        //数组只有一个元素则不处理(处理后数组不会变)
        if (nums.length > 1) {
            while (pj != nums.length) {
                if (nums[pi] == 0 && nums[pj] != 0) {
                    //左指针指向0,右指针指向非零元素,直接交换双指针所指向的两个元素
                    int tmp = nums[pi];
                    nums[pi] = nums[pj];
                    nums[pj] = tmp;
                } else if (nums[pi] == 0 && nums[pj] == 0) {
                    //双指针均指向0,则更新右指针,直至遇到非零元素
                    pj += 1;
                } else if (nums[pi] != 0) {
                    //已进行元素交换,更新双指针
                    pi += 1;
                    pj += 1;
                }
            }
        }
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到