《下篇:龟兔竞速小分队 —— 快慢指针扫荡数组链表》
分为两大子类数组读写快慢指针原地过滤 / 去重slow 维护有效区间fast 遍历全部元素链表快慢指针slow 走 1 步、fast 走 2 步用于找中点、判环、倒数节点。 通用模板 - 数组cpp运行int slow 0; for(int fast 0; fast nums.size(); fast) { if(保留元素条件) nums[slow] nums[fast]; } // slow为有效元素长度通用模板 - 链表cpp运行ListNode* slow head, *fast head; while(fast ! nullptr fast-next ! nullptr) { slow slow-next; fast fast-next-next; }例题 1LeetCode 26 删除有序数组中的重复项题意升序数组原地删除重复元素每个元素只保留一次返回去重后数组长度。完整代码cpp运行#include vector using namespace std; class Solution { public: int removeDuplicates(vectorint nums) { if(nums.empty()) return 0; int slow 0; // slow指向最后一个不重复元素 // fast从第二个元素开始遍历 for(int fast 1; fast nums.size(); fast) { // 发现新的不重复元素 if(nums[fast] ! nums[slow]) { slow; nums[slow] nums[fast]; } } return slow 1; // slow是下标长度需要1 } };逐行解读特判空数组防止访问nums[0]越界slow 记录无重复区间末尾fast 扫描全数组fast 遇到和 slow 不同的值代表新唯一元素slow 右移并覆盖值最终有效长度为slow1下标从 0 开始。易错点返回slow而非slow1漏掉第一个元素长度计算偏小slow 初始化为 1空数组时直接访问nums[1]数组越界先赋值再自增 slow覆盖已保存的有效数据。例题 2LeetCode 27 移除元素题意原地移除数组中等于val的所有元素返回剩余有效长度。完整代码cpp运行#include vector using namespace std; class Solution { public: int removeElement(vectorint nums, int val) { int slow 0; // fast遍历全部元素 for(int fast 0; fast nums.size(); fast) { // 保留不等于val的元素 if(nums[fast] ! val) { nums[slow] nums[fast]; } } return slow; } };逐行解读fast 逐个扫描数组遇到需要保留的元素就写入 slow 位置slow后置自增写入完成后 slow 指向下一个待写入位置循环结束后 slow 的值恰好等于有效元素总个数直接返回。易错点判断条件写反nums[fast]val才赋值保留需要删除的数字逻辑完全颠倒fast 循环上限写成fast nums.size()-1漏掉数组最后一个元素。例题 3LeetCode 141 环形链表链表快慢指针判环题意判断单向链表是否存在环。完整代码cpp运行struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; class Solution { public: bool hasCycle(ListNode *head) { ListNode* slow head; ListNode* fast head; // 必须同时判断fast和fast-next防止空指针解引用 while(fast ! nullptr fast-next ! nullptr) { slow slow-next; // 慢指针走1步 fast fast-next-next; // 快指针走2步 // 快慢指针相遇说明存在环 if(slow fast) return true; } // fast走到空指针无环 return false; } };逐行解读无环时 fast 会率先走到链表末尾nullptr循环结束返回 false存在环时快指针速度更快一定会在环内追上慢指针两节点地址相等判定有环易错点while 条件只写fastfast-next为空时执行fast-next-next空指针解引用程序崩溃循环内先移动指针再判断相等初始 slow 和 fast 都等于 head直接误判存在环。例题 4LeetCode 876 链表的中间结点题意返回链表中间节点偶数长度返回后半段第一个节点。完整代码cpp运行struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; class Solution { public: ListNode* middleNode(ListNode* head) { ListNode* slow head; ListNode* fast head; while(fast ! nullptr fast-next ! nullptr) { slow slow-next; fast fast-next-next; } return slow; } };逐行解读fast 每次两步、slow 每次一步fast 到达链表末尾时slow 刚好停在中点奇数链表slow 指向正中间节点偶数链表slow 指向后半段首节点匹配题目要求。易错点fast 初始化为head-next偶数链表会返回前半段末尾不符合题意循环条件颠倒fast-next fast先访问fast-nextfast 为空时直接崩溃。谢谢