【双指针算法】原地处理数组的双指针算法思想

移动零

5992587c62f74754b2090e2495778db1.png

题目中已经明确表示不能重新创建数组来辅助解题,因此只能对数组进行原地操作,即双指针算法思想。

算法思想:

题目要求我们将非0元素放在数组的左边,0元素放在数组的右边,同时保持非0元素的相对位置。

这种对数组元素进行分类的题目一般用双指针比较合适。

注意:这里的双指针其实指的是数组元素的索引。

首先我们将待处理数组分为三部分区间:非0区间:[0,dest]      0区间:[dest+1,cur-1]     待处理区间:[cur,n-1] 

cur:用于遍历数组遇到非0元素则停止。dest:用于交换非0元素与0元素。

1、cur = 0, dest = -1

2、cur遇到0元素:++cur

      cur遇到非0元素:swap(a[dest+1], a[cur]),然后++dest,++cur

      当cur>n-1则结束。

1925a07b4d024da4a91876d08b2f7345.png

e93b9b5a307141a99a23a58c8510bc88.png

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        for(int cur = 0, dest = -1;cur < nums.size();cur++)
        {
            if(nums[cur])
            swap(nums[cur], nums[++dest]);
        }
    }
};

复写零

e3ef473a94cb4530a05b5b218cfde24e.png

 这道题目要求也是就地进行数组操作,使用双指针是合适的。

算法思想:

先根据“异地”操作然后优化成“就地”操作。下图是通过异地操作获取最后一个“复写”的数。

1、dest = -1,cur = 0,判断a[cur]的值

2、判断dest是否越界 dest <= n-1

3、a[cur] == 0则dest += 2    a[cur] != 0则dest++

4、cur++

a69219f9a462436fa565f67b6896fa6e.png

但是这里有一种特殊情况:

9a2dbc180a884a2aa793ae9d0720ea04.png

找到最后一个复写的元素后按照”从后往前“(因为刚开始从前往后的话,会将后面的元素覆盖掉)的顺序对待处理数组进行复写操作。

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int cur = 0, dest = -1;
        int n = arr.size();
        //先找到最后一个复写的数
        while( cur < n)
        {
            if(arr[cur])
                ++dest;
            else
            dest += 2;
            if(dest >= n-1)
            break;
            ++cur;
        }
        //处理边界情况
        if(dest == n)
        {
            arr[n-1] = 0;
            --cur;
            dest -= 2;
        }
        //最后从后往前复写元素获得所求数组
        while(cur >= 0)
        {
            if(arr[cur])
            arr[dest--] = arr[cur--];
            else
            {
            arr[dest--] = arr[cur];
            arr[dest--] = arr[cur--];
            }
        }
    }
};

  • 26
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值