双指针算法

77 阅读3分钟

001_移动零

链接:283. 移动零 - 力扣(LeetCode)

给定一个数组 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 

进阶: 你能尽量减少完成的操作次数吗?

题解:

算法原理:双指针算法

定义两个指针cur和dest,这里的指针采用的数组下标来充当指针。

两个指针的作用:

  • cur:从左往右遍历数组;

  • dest:已处理区间内,非零元素的最后一个位置;

用这两个指针进行区间划分三个区间:

  • 非0区间:[0, dest]

  • 0区间:[dest + 1, cur - 1]

  • 待处理区间:[cur, n- 1]

操作过程:

cur从左往右遍历过程中:

① 遇到0元素:cur++;

② 遇到非0元素:

dest++;
swap(dest, cur);

代码:

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

002_复写零

链接:1089. 复写零 - 力扣(LeetCode)

给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。

注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。

示例 1:

输入: arr = [1,0,2,3,0,4,5,0]
输出: [1,0,0,2,3,0,0,4]
解释: 调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]

示例 2:

输入: arr = [1,2,3]
输出: [1,2,3]
解释: 调用函数后,输入的数组将被修改为:[1,2,3]

提示:

  • 1 <= arr.length <= 104
  • 0 <= arr[i] <= 9

题解:

算法原理:双指针算法

定义两个指针cur和dest,这里的指针采用的数组下标来充当指针。

① 先判断cur位置的值;

② cur遇到非0元素,dest走一步;cur遇到0元素,dest走两步;

③ 判断一下dest是否到结束位置,若dest没有结束,cur++。

特殊情况:

dest到下标n的位置,已经越界:

下标n-1的位置置为0,cur--,dest -= 2;

最后,“从右往左”完成复写0操作。

代码:

public:
    void duplicateZeros(vector<int>& arr) {
        // 找复写数
        int cur = 0, dest = -1;
        while (cur <= arr.size())
        {
            if (arr[cur])
            {
                // 非0,dest向后走一步
                dest++;
            }
            else
            {
                // 0,dest向后走两步
                dest += 2;
            }
 
            // dest没到边界,cur再往后走一步
            if (dest < arr.size() - 1)
                cur++;
            else
                break;
        }
 
        // 复写0
        while (cur >= 0)
        {
            // 处理特殊情况
            if (dest == arr.size())
            {
                arr[--dest] = arr[cur--];
                --dest;
            }
 
            if (arr[cur])
            {
                // 非0,赋值之后,cur和dest向前各走一步
                arr[dest--] = arr[cur--];
            }
            else
            {
                // 0,赋值给0,dest向前走两步,cur走一步
                arr[dest--] = 0;
                arr[dest--] = 0;
                cur--;
            }
        }
    }
};