关于快慢指针,之前有一个题目,{1,1,1,2,2,2,3,3,3,3}去重;但是现在我们要研究另一个问题
题目
{0,1,0,2,12,3},移动其中的0到最右侧,不能改变其他数值的相对位置;
分析
双指针并不一定全是快慢指针;如果这道题限定了时间复杂度是O(n);那么数组只能遍历一次;
此时重点一定是在元素==0上;
指针A,指向第一个0;
指针B,指向第一个不是0的数字;
| 0 | 1 | 0 | 2 | 12 | 3 |
|---|---|---|---|---|---|
| 指针A | 指针B | ||||
让指针A和指针B指向的元素swap;
| 1 | 0 | 0 | 2 | 12 | 3 |
|---|---|---|---|---|---|
| 指针A | 指针B | ||||
此时指针B向后移动,指向下一个不为0的数字,指针A也向后移动,指向第一个0
| 1 | 0 | 0 | 2 | 12 | 3 |
|---|---|---|---|---|---|
| 指针A | 指针B | ||||
继续交换
| 1 | 2 | 0 | 0 | 12 | 3 |
|---|---|---|---|---|---|
| 指针A | 指针B | ||||
继续交换,然后指针移动
| 1 | 2 | 0 | 0 | 12 | 3 |
|---|---|---|---|---|---|
| 指针A | 指针B | ||||
之后只要按照这个规律移动数据,就能保证最后0都被移动到最右侧;
看起来很简单对吧….但是编码并不是这么简单的…
使用循环遍历数组如何保证循环的时候指针A和指针B在正确的位置;
- 指针A指向第一个元素,指针B指向第二个元素,进行第一轮判断,如果发现符合A->0,B->!0;交换
- 进入第二轮循环,进行判断,指针A是否指向的是0?指针B指向的是!0?如果不是的话,就要发生指针的移动了;指针A如果指向的还是0,指针A不移动;指针A指向的不是0,指针A向后移动一个元素;指针B如果指向的是0,那么指针B向后移动,如果指针B指向的不是0,不发生移动;
- 如果再第二轮循环中,A和B均满足条件,发生交换,如果有一个不满足,进入下一轮循环
-
代码
class Solution {public void moveZeroes(int[] nums) {//排序+环形替换?//并不行,因为给定数组不一定是顺序的..如果排序可能会导致新的数组元素相对顺序不同//使用双指针?if(nums.length==0)return;int guideIndex=1;int laterIndex=0;for(int i=1;i<nums.length;i++){if(nums[laterIndex]==0&&nums[guideIndex]!=0){//swapnums[laterIndex] = nums[guideIndex];nums[guideIndex] = 0;}if(nums[laterIndex]!=0)laterIndex++;if(nums[guideIndex]==0 || guideIndex<=laterIndex)guideIndex++;}}}
误区
一定要保证非0指针位于0指针的后边!!!
