(leetcode) 力扣100 4.移动零(两种O(n)方法 双指针)
题目
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
数据范围
1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
样例
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
题解
博主题解(O(n)略慢于官方题解,但空间复杂度超过百分之99,且思路简单)
public static void moveZeroes(int[] nums) {//第一次遍历处理数据,得到非目标位0的数量int len=nums.length;//记录已遍历0数目int tz=0;for(int i=0;i<len;i++){if(nums[i]==0){tz++;continue;}nums[i-tz]=nums[i];}for(int i=0;i<len;i++){if(i==len-tz){nums[i]=0;tz--;}System.out.print(nums[i]+" ");}}
官方题解 (O(n)双指针,双指针)
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;}
}作者:力扣官方题解
链接:https://leetcode.cn/problems/move-zeroes/solutions/489622/yi-dong-ling-by-leetcode-solution/
来源:力扣(LeetCode)
思路
这道题整体思路简单,但题目提到,不能新建数组,那么目的很明确了,就是要求你在O(1)的空间复杂度和O(n)的时间复杂度完成这道题。
博主采用的思路很简单,不管原始数组如何,最后得到的数组形式是一样的,前面一串非0数字,最后几个连续的0,那么就不需要考虑交换的逻辑,而是去把数字放到他最后应该存在的位置即可。这个很容易实现,使用tz存储目前遍历位置已经出现过0的数量,然后将非0数字往前移动就好。在遍历的过程中顺便记录0的个数,最后再把0填充到数组末端即可。
官方题解的思路需要熟悉双指针的思路,双指针有两种常见思路。第一种两个指针同时从一侧出发,类似快慢指针。第二种两个指针分别从两侧出发。这道题我们经过判断后,选择第一种,left用来存储非零数字目前应该存储的位置,right用来作为枚举的效果。通过交换 left 和 right 的元素,确保left 左侧全是非零元素(且顺序不变),left 和 right 之间是零(如果有)。
整体来说,对于没接触过或不熟悉双指针的人来说,官方题解虽然优雅,但还是具有一定的思维难度,大家多联系即可。