539.移动零

描述

给一个数组 nums 写一个函数将 0 移动到数组的最后面,非零元素保持原数组的顺序

注意事项

1.必须在原数组上操作
2.最小化操作数

样例

给出 nums = [0, 1, 0, 3, 12], 调用函数之后, nums = [1, 3, 12, 0, 0].

知识点

相向,同向型两根指针一直往前走,时间复杂度都为 O(n),若左指针前进一步右指针回到初始位置重新走的话时间复杂度为 O(n^2),两根指针一般用在 O(n) 的时间复杂度,要比 O(nlogn) 快

思路

用同向型指针,一个指向第一个为 0 的元素,一个指向第一个不为 0 的元素, 在向右移动过程中不断把 0 交换到数组的末尾

代码

  1. 统计数组中 0 的个数,把不为 0 的数按照顺序全部加入到动态数组中,然后在按照统计个数把 0 加入,最后用数组复制下动态数组中的元素,时间复杂度 O(n) 空间复杂度 O(n)
public class Solution {
    /*
     * @param nums: an integer array
     * @return: 
     */
    public void moveZeroes(int[] nums) {
        int count = 0;
        ArrayList<Integer> array = new ArrayList<>();
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != 0) {
                array.add(nums[i]);
            } else {
                count++;
            }
        }
        
        while (count-- != 0) {
            array.add(0);
        }
        
        for (int i = 0; i < nums.length; i++) {
            nums[i] = array.get(i);
        }
    }
}
  1. 遍历过程中直接把非 0 数全拷贝到 nums 数组中,后面空位全部补 0,时间复杂度 O(N),空间复杂度 O(1)
    不存在非 0 数被覆盖的情形,0 被覆盖,非 0 数停留在原地
public class Solution {
    /*
     * @param nums: an integer array
     * @return: 
     */
    public void moveZeroes(int[] nums) {
        int lastNoZeroIndex = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != 0) {
                nums[lastNoZeroIndex++] = nums[i];
            }
        }
        
        for (int i = lastNoZeroIndex; i < nums.length; i++) {
            nums[i] = 0;
        }
    }
}
  1. 上一种的时间复杂度在遍历完一遍数组后又遍历了 0 的个数,用两根指针优化时间复杂度,让算法只遍历一遍数组,时间复杂度 O(N),空间复杂度 O(1)
    AAA000BC ————> AAAB000C
    left 始终指向第一个0只是下标在移动,right 刚开始指向 B,交换完后后移一位指向 C,始终是指向第一个非 0 数
public class Solution {
    /*
     * @param nums: an integer array
     * @return: 
     */
    public void moveZeroes(int[] nums) {
        // left 代表数组中第一个值为 0 的下标
        // right 代表数组中第一个值不为 0 的下标
        int left = 0, right;
        for (right = 0; right < nums.length; right++) {
            if (nums[right] != 0) {
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;
                /* 在没遇到第一个 0 之前,right 每移动一次 left 也跟着移动,
                 * left 和 right 始终指向同一元素,交换也是自己和自己的交换,
                 * 所以不会出现如果数组第一个元素不是 0,right++跑到 0,
                 * 而 left 仍在数组第一个元素处不动的反向交换情形
                 */
                left++;
            }
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 14,349评论 0 33
  • 给一个数组 nums 写一个函数将 0 移动到数组的最后面,非零元素保持原数组的顺序样例给出 nums = [0,...
    和蔼的zhxing阅读 1,729评论 0 0
  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 8,808评论 3 44
  • 现在不少APP都集成了支付宝支付功能,要想使用支付宝进行一个完整的支付功能,大致有以下几个步骤: 向支付宝申请,与...
    论丶道阅读 3,499评论 2 5
  • 卓麦阅读 1,235评论 1 1