数组的双指针一般分为两类:

  • 1 快慢指针
  • 2 左右指针:相向指针和同向指针包括滑动窗口。

1 快慢指针

快慢指针的常见用处是原地修改数组。

快慢指针的使用是有限制的,即数组必须有序,或者限定锚点值。

常见解题思路:

  • 1 快指针寻找与慢指针处结果不同或者与标准结果不同的结果。
  • 2 返回或者待处理的值是慢指针的位置。

经典题目:

  • 1 删除有序数组中的重复项
  • 2 删除排序链表中的重复元素
  • 3 移除元素
  • 4 移动零

经典模版:

int removeDuplicates(vector& nums) {
    if (nums.size() == 0) {
        return 0;
    }
    int slow = 0, fast = 0;
    while (fast < nums.size()) {
        if (nums[fast] != nums[slow]) {
            slow++;
            // 维护 nums[0..slow] 无重复
            nums[slow] = nums[fast];
        }
        fast++;
    }
    // 数组长度为索引 + 1
    return slow + 1;
}

2 左右指针

相向指针和同向指针(滑动窗口)具体可以见:双指针 – 相向/同向双指针

相向指针的经典题目:

  • 1 两数之和,三数之和,四数之和。
  • 2 二分查找。
  • 3 反转数组,回文串判断,最长回文串。

同向指针的经典题目:

  • 1 长度最小的子数组
  • 2 乘积小于k的子数组
  • 3 无重复字符的最长子串

滑动窗口的模版:

  • 1 右移增大窗口
  • 2 左移缩小窗口
/* 滑动窗口算法框架 */
void slidingWindow(string s) {
    unordered_map<char, int> window;

    int left = 0, right = 0;
    while (right < s.size()) {
        char c = s[right];
        // 右移(增大)窗口
        right++;
        // 进行窗口内数据的一系列更新

        while (window needs shrink) {
            char d = s[left];
            // 左移(缩小)窗口
            left++;
            // 进行窗口内数据的一系列更新
        }
    }
}