Day 13。
今天两道题分别是 Remove Duplicates from Sorted ArrayRemove Element
这两题非常经典,而且可以说是:

双指针(快慢指针)入门模板题

今天的关键词:快慢指针、原地修改、覆盖写入、数组去重


🧠 LeetCode 26 – Remove Duplicates from Sorted Array

💡 思路总结

这题要求:

  • 有序数组中删除重复元素
  • 并返回去重后的长度
  • 必须原地修改

因为数组是有序的,所以重复元素一定是挨在一起的。

你的思路非常标准:

用快慢指针,把不重复的元素往前覆盖


💻 代码实现

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if(nums.empty())return 0;
        int slow = 0 ;
        for(int fast = 1;fast<nums.size();fast++){
            if(nums[fast] != nums[slow]){
                slow++;
                nums[slow] = nums[fast];
            }
            
        }
        return slow+1;
    }
};

📌 知识点总结

1️⃣ 快慢指针的含义

  • slow:表示当前“有效数组”的最后一个位置
  • fast:负责遍历整个数组

逻辑就是:

  • fast 负责找新元素
  • slow 负责维护结果

2️⃣ 为什么能这样做(有序是关键)

因为数组是有序的:

1 1 2 2 3 3

重复的元素一定连续出现。
所以只需要比较:

nums[fast] != nums[slow]

就能判断是不是新元素。


3️⃣ 覆盖写入思想

nums[slow] = nums[fast];

这一步非常关键,本质是:

把“有效元素”往数组前面重新排列

后面的内容不重要,因为题目只关心前 k 个。


4️⃣ 返回值为什么是 slow + 1

因为 slow 指向的是:

  • 最后一个有效元素的位置(下标)

所以长度是:

slow + 1

🔥 LeetCode 27 – Remove Element

💡 思路总结

这题和上一题很像,但有一个关键区别:

  • 上一题:删除重复元素(有序)
  • 这一题:删除指定值(无序)

不过思路是完全一样的:

保留需要的元素,覆盖到前面


💻 代码实现

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        if(nums.size()==0)return 0;
        int slow = 0;
        for(int fast =0;fast<nums.size();fast++){
            if(nums[fast] != val){
                nums[slow] = nums[fast];
                slow++;
            }
        }

        return slow;
            
    }
};

📌 知识点总结

1️⃣ 和上一题的统一模板

你可以发现,这两题本质是同一个模板:

for fast 遍历数组:
    如果当前元素是“有效的”:
        写到 nums[slow]
        slow++

区别只在于:

题目判断条件
26nums[fast] != nums[slow]
27nums[fast] != val

2️⃣ 无序数组也能用

这题没有排序,但依然可以用这个方法,因为:

  • 我们不关心顺序
  • 只关心“把有效元素放前面”

3️⃣ 为什么可以覆盖自己

很多人一开始会担心:

nums[slow] = nums[fast];

会不会覆盖还没处理的数据?

答案是不会,因为:

  • slow <= fast
  • 写的位置永远在“已处理区域”内

4️⃣ 返回值就是有效长度

return slow;

因为 slow 最终停在:

  • 第一个无效位置
  • 也就是有效元素的数量

🧩 两题放在一起看

今天这两题可以总结成一个非常重要的模板:

🔥 数组原地过滤模板

int slow = 0;
for(int fast = 0; fast < nums.size(); fast++){
    if(当前元素是有效的){
        nums[slow] = nums[fast];
        slow++;
    }
}
return slow;

🧠 今日收获

今天最重要的不是两道题本身,而是你掌握了一个超级高频模板

1. 快慢指针(数组版)

用途:

  • 去重
  • 删除元素
  • 保留符合条件的元素

2. 原地修改数组

这种题有一个典型特征:

  • 不允许额外空间
  • 返回有效长度
  • 不关心后面的内容

遇到这种题,基本可以直接往“覆盖写入”方向想。


💬 写给自己的话

Day 13 了。

你现在已经开始掌握一些真正“可以复用”的模板了:

  • 双指针(数组)
  • 双指针(链表)
  • 回溯
  • 去重逻辑

这说明你已经从“做题”开始走向:

理解题型

这是一个很重要的阶段。

接下来你会发现一件很爽的事情:

  • 有些题一眼就知道怎么写
  • 有些题甚至不用想太久

那就是题感在慢慢形成。

继续坚持。
你现在不是在刷题,是在搭自己的“算法体系”。

阿玉,Day 13,继续冲。你已经越来越像一个真正会做题的人了。

—— 刷题第 13 天