题目描述:
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。
题目解析:
- 暴力法,遍历数组,遇到0就将后面往前移动,并从后往前给数组末尾赋值0
void MoveZeroes(int *arr,int len)
{
int count = 0;
for(int i = 0;i<len;++i)
{
if(arr[i] == 0)
{
count ++;
for(int j = i;j<len-1;++j)
{
arr[j] = arr[j+1];
}
//每挪动一次,从数组最后赋值0一次
arr[len-count] = 0;
}
}
}
- 双指针法:
假设数组:
一开始i和j指向0,j的含义是将来存放下一个非0元素,i = 1时,交换0和6:
6 0 1 0 3 4 9 0
此时i = 2,j =1,继续将元素1向前移动:
6 1 0 0 3 4 9 0
以此类推,最终非0有序的被挪动到前面,所有0被局限在(i,j)之间,遍历完成后既然就到了数组末尾。
void MoveZeroes(int *arr,int len)
{
//记录下一个非0元素放入的位置,i遍历到的非0元素与j下标元素进行交换
int j = 0;
//i遍历数组,找非0的元素,找到了就与j交换
for(int i = 0;i< len;++i)
{
//不等于0 将该元素向前移动
if(arr[i] != 0)
{
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
//保证j始终保持指向0
++j;
}
}
}
- 优化双指针:当arr[i]和arr[j]相等的时候就不需要交换元素
void MoveZeroes(int *arr,int len)
{
//记录下一个非0元素放入的位置,i遍历到的非0元素与j下标元素进行交换
int j = 0;
//i遍历数组,找非0的元素,找到了就与j交换
for(int i = 0;i< len;++i)
{
//不等于0 将该元素向前移动
if(arr[i] != 0)
{
if(arr[i] != arr[j])
{
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
//保证j始终保持指向0
++j;
}
}
}
- 再次优化双指针:用赋值的方式代替交换
void MoveZeroes(int *arr,int len)
{
int j = 0;
for(int i = 0;i< len;++i)
{
if(arr[i] != 0)
{
if(arr[i] != arr[j])
{
arr[j] = arr[i];
}
//保证j始终保持指向0
++j;
}
}
//最后将末尾j-len之间的元素赋值为0
for(int i = j;j < len; ++j)
{
arr[i] = 0;
}
}