给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
提示:
1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
进阶:你能尽量减少完成的操作次数吗?
解题思路1:
- 1.使用一前一后两个下标,front用于扫描,rear用于移动确定非零元素的位置。
- 2.front扫描结束后,将rear下标之后的数据清零。
void moveZeroes(int* nums, int numsSize){
int front = 0;
int rear = 0;
for(front = 0; front < numsSize; front++) {
if (nums[front] != 0) {
nums[rear] = nums[front];
rear++;
}
}
memset(nums + rear, 0, sizeof(int) * (numsSize - rear));
}
解题思路2:
使用双指针,左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换,同时左指针右移。
注意到以下性质:
- 左指针左边均为非零数;
- 右指针左边直到左指针处均为零。
因此每次交换,都是将左指针的零与右指针的非零数交换,且非零数的相对顺序并未改变。
双指针交换法(该题的本质是考察双指针,i 代表右指针,j代表左指针)
0 1 0 3 12
i
j
0 1 0 3 12 i指向数组第1个非零数,准备交换nums[i]和nums[j],即准备交换1和0
i
j
1 0 0 3 12
i swap(&nums[i], &nums[j])交换,即1和0交换完成(第1轮交换)
j
1 0 0 3 12
i i移动到下一个非0数字,j向前移动1步,准备交换nums[i]和nums[j],即准备交
j
换3和0
1 3 0 0 12
i swap(&nums[i], &nums[j])交换,即3和0交换完成(第2轮交换)
j
1 3 0 0 12
i i移动到下一个非0数字(刚好是数组结尾),j向前移动1步,准备交换nums[i]和
j
nums[j],即准备交换12和0
1 3 12 0 0
i swap(&nums[i], &nums[j])交换,即12和0交换完成(第3轮交换)。由于i已经
j
到达数组结尾,因此结束。
void swap(int *a, int *b) {
int t = *a;
*a = *b, *b = t;
}
void moveZeroes(int *nums, int numsSize) {
int left = 0, right = 0;
while (right < numsSize) {
if (nums[right]) {
swap(nums + left, nums + right);
left++;
}
right++;
}
}
解题思路3:遍历
void moveZeroes(int *nums, int numsSize)
{
for(int k=1;k<=numsSize;k++)
{
for(int i;i+1<numSize;i++)
{
if(num[i]==0&&num[i+1]!=0)
{
count++;
int t=num[i];
num[i=num[i+1];
num[i+1]=t;
break;
}
}
}
return;
}