图解算法——数组移动零
1、题目描述
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/move-zeroes 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2、示例
示例1:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
- 必须在原数组上操作,不能拷贝额外的数组;
- 尽量减少操作次数。
3、解题思路
看到这道题,由于题目限制了不能有额外空间消耗,所以暴力法求解思路是:从前往后遍历(或从后往前遍历),遇到一个0,就进行类似 “冒泡” 排序的操作,将0 移动到数组最后。
代码如下:
class Solution { public void moveZeroes(int[] nums) { int l = 0; int r = nums.length-1; for(int i = r; i>=l; i--){ if(nums[i] == 0){ for(int j = i; j<r; j++){ nums[j] = nums[j+1]; } nums[r] = 0; r--; } } } }
问题似乎解决了,我们提交一下看看结果如何:
果然,耗时是比较严重的,拖了后腿。
因为在这里你的算法复杂度是O(N^2);
那么有没有复杂度为O(n)的办法呢?
当我们看到这里,不知道有没有思路想到“双指针”?
是的,一般情况下,双指针就是解决数组元素交换问题的。但是有人说了,上面的思路不就是双指针嘛?
是的,上面的思路也是双指针,不过不同的是,上面的思路是一左一右指针。左指针是固定的,不会变,只有右指针在变化。
而下面这个思路是,左右指针都在变化。我们设定一左一右指针left 和 right,且初始值都是0。
我们以right 为驱动,当right 下标所在位置不为0 时,我们交换left 和 right两个位置的数据,然后left++ 且 right ++;当right 下标处不为0 时,right ++。这里left 代表数组左侧第一次以0 开头元素下标(如:数组 [5,6,8,7,0,0,3],left就是下标为4的0元素),right 表示右侧遍历的下标。
故,代码如下:
class Solution { public void moveZeroes(int[] nums) { int n = nums.length, left = 0, right = 0; while (right < n) { if (nums[right] != 0) { swap(nums, left, right); left++; } right++; } } public void swap(int[] nums, int left, int right) { int temp = nums[left]; nums[left] = nums[right]; nums[right] = temp; } }
提交看看:
果然,由于时间复杂度的降低,耗时果然减少了许多。
小结:
注意在数组中双指针的使用。
Over......