283. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12] 输出: [1,3,12,0,0]
说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。
思路一:
快慢指针,慢指针指向下个非零元素应该放置的位置,快指针寻找下个非零元素, 快指针找到非0元素后把元素赋值为慢指针所在位置的元素,最后把慢指针到末尾的所有元素都置为0
1 class Solution { 2 public void moveZeroes(int[] nums) { 3 if(nums == null){ 4 return; 5 } 6 7 int noneZeroIndex = 0; 8 int n = nums.length; 9 for(int i = 0; i < n; i++){ 10 if(nums[i] != 0){ 11 nums[noneZeroIndex++] = nums[i]; 12 } 13 } 14 // 把noneZeroIndex部分的所有元素都置为0 15 Arrays.fill(nums, noneZeroIndex, n, 0); 16 } 17 }
力扣测试时间为0ms, 空间为40.2MB
复杂度分析:
时间复杂度为O(n)
空间复杂度为O(1)
思路二:
对上面的解法做了一点小改进,在判断nums[i]非零时,交换nums[i]和nums[noneZeroIndex]两个元素,而非仅仅给nums[noneZeroIndex]赋值,这样可以去除第二轮迭代。之所以选择交换而非直接给nums[i]赋值为0, 是因为,如果刚好i == noneZeroIndex, 那么将引发错误。
1 class Solution { 2 public void moveZeroes(int[] nums) { 3 if(nums == null){ 4 return; 5 } 6 7 int noneZeroIndex = 0; 8 int n = nums.length; 9 for(int i = 0; i < n; i++){ 10 if(nums[i] != 0){ 11 int temp = nums[noneZeroIndex]; // 交换noneZeroIndex和i的元素 12 nums[noneZeroIndex++] = nums[i]; 13 nums[i] = temp; 14 } 15 } 16 } 17 }
力扣测试时间为:0ms, 空间为:39.9MB
复杂度分析:
时间复杂度为O(n)
空间复杂度为O(1)
1 class Solution { 2 public void moveZeroes(int[] nums) { 3 // 快慢指针,慢指针指向下个非零元素应该放置的位置,快指针寻找下个非零元素 4 int fast = 0, slow = 0; 5 int len = nums.length; 6 while(fast != len){ 7 // 快指针如果碰到非0元素,就与慢指针所指元素进行交换,否则后移一位,交换后慢指针后移一位 8 if(nums[fast] != 0){ 9 int temp = nums[fast]; 10 nums[fast] = nums[slow]; 11 nums[slow] = temp; 12 slow++; // slow指向下个非零元素应该存放的位置 13 } 14 fast++; 15 } 16 } 17 }
思路三:
同样是快慢指针
遍历数组,把当前0与下一个非0元素进行交换
1 class Solution { 2 public void moveZeroes(int[] nums) { 3 if(nums == null){ 4 return; 5 } 6 7 // 遍历数组,把当前0与下一个非0元素进行交换 8 int n = nums.length; 9 int j= 0; 10 for(int i = 0; i < n; i++){ 11 if(nums[i] == 0){ 12 for(j = j + 1; j < n && nums[j] == 0; j++); // 查找下一个不为0的数字 13 if(j < n){ // 如果j < n, 交换nums[i] 和nums[j] 14 nums[i] = nums[j]; 15 nums[j] = 0; 16 }else{ 17 break; // 如果j >= n,说明0已经全被移动到了末尾 18 } 19 }else{ 20 j++; 21 } 22 23 } 24 } 25 }
力扣测试时间为0ms, 空间为:39.8MB
复杂度分析:
时间复杂度:i和j指针都只遍历了一次数组,所以时间复杂度为O(n),
空间复杂度: 为O(1)
另一种写法
1 class Solution { 2 public void moveZeroes(int[] nums) { 3 // 快慢指针,慢指针指向下个非零元素应该放置的位置,快指针寻找下个非零元素 4 int fast = 0, slow = 0; 5 int len = nums.length; 6 for(; slow < len; slow++){ 7 if(nums[slow] == 0){ // 当前位置是下个非0元素的存放位置 8 // 快指针寻找下个非0元素 9 for(; fast < len && nums[fast] == 0; fast++); 10 if(fast < len){ 11 nums[slow] = nums[fast]; 12 nums[fast] = 0; 13 }else{ 14 break; 15 } 16 } 17 fast++; // 遇到非0元素或者交换位置后向后移动一格 18 } 19 } 20 }
思路参考:
https://leetcode-cn.com/problems/move-zeroes/solution/yi-dong-ling-by-leetcode/