快慢指针用于数组的原地处理

发布时间 2023-10-09 11:36:44作者: HDD-SG
  • 删除指定元素

27. 移除元素

  • 删除有序数组的重复项

26. 删除有序数组中的重复项

  • 删除有序数组重复项超过K次的部分

80. 删除有序数组中的重复项 II

整体来说,这类题目所用的方法都是快慢指针,只是其实现细节不尽相同而已。
对我来说,做这种题目最好自己在纸上写写,不然很容易细节上出现问题。
从细节上来说,快慢指针在什么情况下需要进行逻辑处理才是这类题目的关键,也即nums[fast] 与 val/nums[slow]处于什么条件时我们需要进行处理。我个人常常陷入一个误区:我的关注点常常在于处理nums[fast] == val/nums[slow]的情况,也就是题目要求处理的那一类情况,但是,对于数组来说,储存是连续的,也就是说,赋值与覆盖是持续的,考虑的仅仅是fast什么时候赋值,什么时候仅仅移动。
我暂时的理解是:只有作为fast指针满足目标条件是,slow指针都得进行承接工作。其实题目往往隐藏了,不满足目标条件时的处理,也即fast指针的前进,其实fast的前进是每次都进行的,所以也没必要加一个if循环了。

// 27. 移除元素
int removeElement(vector<int>& nums, int val) {
    int fast = 0, slow = 0;
    while (fast < nums.size()) {
        if (nums[fast] != val) {   // 满足目标条件,即删除val,即fast != val时承接。
            nums[slow] = nums[fast];
            slow++;
        }
        fast++;
    }
    return slow;
}
// 26. 删除有序数组中的重复项
int removeDuplicates(vector<int>& 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;
}
// 80. 删除有序数组中的重复项 II
int removeDuplicates(vector<int>& nums) {
        int n = nums.size();
        if (n <= 2) {
            return n;
        }
        int slow = 2, fast = 2;
        while (fast < n) {
            if (nums[slow-2] != nums[fast]) {  // 满足要求。
                nums[slow] = nums[fast];
                ++ slow;
            }
            ++ fast;
        }
        return slow; // 比实际下标+1
    }