持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
题目
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
解题思路
关键词:0移动到数组末尾;保持相对顺序;
关键信息:需要保持相对顺序;
低效双指针解法
数组排序位移最先想到的还是双指针解法。利用首尾指针遍历数组将首指针的0后移到尾部。
- 创建双指针初始化分别指向0,nums.length - 1。
- 遍历右指针直到不为零为止。
- 遍历左指针直到为零为止。
- 两个条件都满足就交换两个值。
- 遍历完成后再判断是否还有剩余数值填充到数组最后。
public void moveZeroes(int[] nums) {
int i = 0,j = nums.length - 1; // 左右指针分别先指向数组首和尾部
while(i < j){
while(nums[j] == 0) j--;
while(nums[i] != 0) i++;
if(nums[i] == 0){
nums[i++] = nums[j];
nums[j--] = 0;
}
}
// 剩余值遍历
int i = 0,j = 1,length = nums.length;
while(i < j && j < length){
while(nums[j] != 0) j++;
while(nums[i] != 0) i++;
}
}
该解法可以实现将0移动到数组后方,但根据题意“保持非零元素的相对顺序”没有实现。若要保证相对顺序使用双指针首尾判断就不合适了。
保持相对顺序解法双指针方式就是指针依靠。i和j相邻,i做步进操作,j在i之后做遍历直到i遍历结束。
- i步进到0数值,j=i+1接着遍历j直到非0为止。
- 交换i和j数值,i++继续步进到非0。
- 重复上述步骤直到遍历结束。
public void moveZeroes(int[] nums) {
int i = 0,j = i + 1;
while(i < nums.length){
while(i < nums.length && nums[i] != 0) i++; // 为0为止
j = i + 1;
while(j < nums.length && nums[j] == 0) j++; // 非0为止
if(j < nums.length && i < nums.length){
nums[i] = nums[j];
nums[j] = 0;
}
i++;
}
}
高效解法
高效解法思路正好和上述解法相反,通过移动right指针找到非0数值将其和left指针值做交换。因为left和right都是以0下标初始化,因此right移动肯定不会忽略过任何为0数值。left指向值肯定都是0的数值。
- left和right初始化指针指向0下标
- 循环过程当right小于数组长度
- right指向不为0的情况时对left和right做交换,同时两个指针都前移
public void moveZeroes(int[] nums) {
int n = nums.length, left = 0, right = 0;
while (right < n) { // 小于数值长度
if (nums[right] != 0) { // 右边不为0时 左右替换
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
left++; // 左边指针移动
}
right++; //右边指针移动
}
}
参考
- 来源:力扣(LeetCode)