
描述
Given an array nums, write a function to move all 0’s to the end of it while maintaining the relative order of the non-zero elements.
Example:
Input: [0,1,0,3,12]
Output: [1,3,12,0,0]
Note:
You must do this in-place without making a copy of the array.
Minimize the total number of operations.
思路
解一
设置两个指针i、j,用i指向为0的数字,用j指向不为0的数字。只有当j>i的时候,才需要交换nums[i],nums[j]。那么先遍历一遍数组,用i来表示,如果nums[i]不为0,跳过;如果为0,才有可能交换。然后将i赋值给j,找到i之后的为0的下标,交换nums[i],nums[j]。注意i、j不能越界。
1 | public static void moveZeroes1(int[] nums) { |
该算法的时间复杂度不理想,最坏情况下是 O(N^2)
解二
参考冒泡的思想,两个之间逐个比较,如果有前面的那个为0,就交换位置。利用其稳定性,可以保证不为0元素的顺序。
1 | public static void moveZeroes2(int[] nums) { |
按照冒泡思想可以优化,优化后的最好时间复杂度为O(N),最坏还是 O(N^2)
解三
对解一的优化,避免多余的比较和查找。利用双指针的优势,将时间复杂度压缩到O(N),思路如下:
设置两个指针i、j,用i指向不为0的数字,用j指向为0的数字。只有当i>j的时候,才需要交换nums[i],nums[j]。i、j分别从0开始,如果nums[i]==0,i++;如果nums[j]!=0,j++;如果i>j并且nums[i] != 0,交换i,j的值,并且同时加一,否则i++;注意边界不超过len。
1 | public static void moveZeroes3(int[] nums) { |
该程序注意死循环问题,为了避免死循环,才需要i++。该程序最坏要走2N部,时间复杂度为O(n)。另外我们swap也能进行优化,因为我们知道nums[j] = 0
nums[j] = nums[i];
nums[i] = 0;
参考
参一
统计出不为0的个数,将不为0的赋值给数组前几位,后续的用0补充
1 | // 参考 |
时间复杂度O(N)
参二
快慢指针思想,j是慢指针,指向为0的元素,i是快指针为不为0元素。快指针将所有不为0的元素,赋值给前面为0的元素,直到全为0。
1 | public static void moveZeroes5(int[] nums) { |
时间复杂度O(N)
github
代码地址对应的是提交记录,方便参看当时踩过的坑。