283. 移动零
难度 简单
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
- 必须在原数组上操作,不能拷贝额外的数组。
- 尽量减少操作次数。
题解
这道题从示例就很容易知道把所有0移动到最后,然后开始就想着,用选择排序的思想,每次选到0就移动数组,把0放到最后。
解法一
void modify(int *nums,int start,int end){
int temp=nums[start];
for(int i=start;i<end;i++){
nums[i]=nums[i+1];
}
nums[end]=temp;
}
void moveZeroes(int* nums, int numsSize){
int end=numsSize-1;
for(int i=numsSize-1;i>=0;i--){
if(nums[i]==0){
modify(nums,i,end);
end--;
}
}
}
解法二
虽然能AC,但是很明显效率不高,没遇到0都需要移动数组,有没有更好的想法呢,但是想了几分钟,没有想到,就看题解去了。官方的题解是用了双指针,刚开始看到时候不太明白,如果交换,呢会不会打破原来非零元素的顺序(类似排序算法的稳定性)。看代码不太模拟的出来,就在草稿子上手动模拟了一下,好家伙,既然没有破坏顺序。
-
左右指针用来干什么
左指针l指向零元素,右指针r指向非零元素,当右指针r指向非零元素时,就可以交换,这样就把零元素往后移动,非零往前往前移,满足要求。
-
为什么没有破坏原来非零元素的稳定性呢?
当nums[r]不等于0时才l++,但是r一直++,这使得r永远大于等于l。所以越后面的零,交换的数则放在越后
-
那零元素的稳定性会不会影响结果
很明显,不影响结果,题目只是要求把零元素放在最后,没有要求其他。
void swap(int* a,int* b){
int temp=*a;
*a=*b;
*b=temp;
}
void moveZeroes(int* nums, int numsSize){
int l=0;//左指针,指向零元素下标
int r=0;//右指针,指向非零元素下标
while(r<numsSize){
if(nums[r]){//右指针不为零元素
swap(nums+l,nums+r);//nums是数组头地址,+l表示数组l下标地址
l++;//左指针右移
}
r++;//右指针右移
}
}