目录
1. 移动零
1.1 思路解析
1.2 代码实现
2. 复写零
2.1 思路解析
2.2 代码实现
1. 移动零
283. 移动零 - 力扣(LeetCode)
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]输出: [0]
我们可以用双指针来解决上方问题,这里的双指针用数组下标代替与C++的指针作区分。此问题不涉及整个数组的平移。
1.1 思路解析
a)先定义两个指针,dest 和 cur,我们可以让 cur 来遍历整个数组。
b)我们可以用双指针来把整个数组分为三个区域:[0,dest] 非零区域、[dest+1,cur-1] 零区域、[cur,n-1] 待处理区域。上述问题我在之后将统一称为数组划分问题。
c)具体的思路是,让 cur 从零开始,dest 从 -1位置开始。当 cur 遇到零元素时跳过 cur++,当 cur 遇到非零元素时 dest++ ,并且让当前 cur 所指元素和 dest++ 后的所指元素交换位置。
1.2 代码实现
class Solution {public void moveZeroes(int[] nums) {for(int cur = 0,dest = -1; cur<nums.length;cur++){if(nums[cur] != 0){int tmp = nums[cur];dest++;nums[cur] = nums[dest];nums[dest] = tmp;}}}
}
2. 复写零
1089. 复写零 - 力扣(LeetCode)
2.1 思路解析
a)我们可以定义双指针来解决该问题,定义 cur 和 dest。
b)cur 遇到的情况分为两种,遇到零 和 非零元素。
c)我们可以让 cur 遇到非零元素时,dest 在当前位置复写一个;同理 cur 遇到零元素时,dest 在当前位置和后一位复写两个零。
但是如果我们从左往右来进行操作,如果遇到 [1,0,2,1] 这种数组的话,操作结果就不符合题目要求,因为 dest 已经在 cur 前面了,会造成数据丢失。如下图所示:
所以我们需要转变思路:
a)先找到最后一个复写的数
先定义两个指针 cur 和 dest,让 cur 的初始值为0,dest 初始值为 -1。让 dest 走 cur 遍历的数来判断最后一个复写的数。当 cur 遇到非零元素时,dest 移动一位,cur 遇到零元素时,dest 移动两位。当 dest 遍历完整个数组时,cur 所指的下标就是最后一个复写的数。
b)处理边界问题
当我们遇到类似 [2,0,3,5,0,4] 这样的数组时就会发生 dest 所在的位置越界情况,从后向前的复写操作就会报错,解决方案就是 arr[dest-1] = 0; cur --;dest -= 2。越界情况如下图所示:
c)从后向前完成复写操作
当 cur 遇到非零元素时,把 cur 的元素覆盖到 dest 所在的位置,arr[dest--] = arr[cur--];当 cur 遇到零元素时,把零元素覆盖到 dest 当前位置和前一位。
2.2 代码实现
class Solution {public void duplicateZeros(int[] arr) {int cur = 0, dest = -1;while(cur<arr.length){if(arr[cur] == 0){dest += 2;}else{dest ++;}if(dest>=arr.length-1){break;}cur++; }if(dest == arr.length){arr[dest-1] = 0;dest -= 2;cur --;}while(cur>=0){if(arr[cur] == 0){arr[dest--] = 0;arr[dest--] = 0;cur--;}else{arr[dest--] = arr[cur--];}}}
}