双指针基础概念双指针技术通常用于数组或链表等线性结构中通过两个指针协同遍历来优化时间复杂度。主要分为以下类型同向指针两个指针从同一侧出发移动速度不同对向指针两个指针分别从首尾向中间移动快慢指针常用于环形链表检测同向指针应用移除重复元素给定排序数组原地移除重复元素并返回新长度。int removeDuplicates(vectorint nums) { if(nums.empty()) return 0; int slow 0; for(int fast 1; fast nums.size(); fast){ if(nums[fast] ! nums[slow]){ nums[slow] nums[fast]; } } return slow 1; }练习题1移除指定值给定数组nums和值val原地移除所有val实例。练习题2合并两个有序数组将nums2合并到nums1中假设nums1有足够空间。对向指针应用两数之和II在有序数组中找出两个数使它们的和等于目标值。vectorint twoSum(vectorint numbers, int target) { int left 0, right numbers.size() - 1; while(left right){ int sum numbers[left] numbers[right]; if(sum target) return {left1, right1}; else if(sum target) left; else right--; } return {}; }练习题3盛最多水的容器给定高度数组找出两条线使得容器能盛最多水。练习题4三数之和找出数组中所有和为0的三元组。快慢指针应用环形链表检测判断链表中是否有环。bool hasCycle(ListNode *head) { ListNode *slow head, *fast head; while(fast fast-next){ slow slow-next; fast fast-next-next; if(slow fast) return true; } return false; }练习题5寻找环形入口给定有环链表返回环的起始节点。练习题6链表中点找到链表的中间节点偶数时返回第二个。滑动窗口变种最小覆盖子串在字符串S中找到包含T所有字符的最短子串。string minWindow(string s, string t) { unordered_mapchar, int need; for(char c : t) need[c]; int left 0, cnt 0, min_len INT_MAX, start 0; for(int right 0; right s.size(); right){ if(need[s[right]]-- 0) cnt; while(cnt t.size()){ if(right - left 1 min_len){ min_len right - left 1; start left; } if(need[s[left]] 0) cnt--; left; } } return min_len INT_MAX ? : s.substr(start, min_len); }练习题7字符串排列判断s2是否包含s1的排列。练习题8无重复字符的最长子串多序列指针合并K个排序链表使用优先队列优化多指针比较。struct Compare { bool operator()(ListNode* a, ListNode* b){ return a-val b-val; } }; ListNode* mergeKLists(vectorListNode* lists) { priority_queueListNode*, vectorListNode*, Compare pq; for(auto list : lists) if(list) pq.push(list); ListNode dummy(0); ListNode* tail dummy; while(!pq.empty()){ auto node pq.top(); pq.pop(); tail-next node; tail tail-next; if(node-next) pq.push(node-next); } return dummy.next; }练习题9两个数组的交集II计算两个数组的交集出现次数一致。练习题10最长公共前缀查找字符串数组中的最长公共前缀。特殊场景应用回文链表判断结合快慢指针和链表反转。bool isPalindrome(ListNode* head) { if(!head || !head-next) return true; ListNode *slow head, *fast head; while(fast fast-next){ slow slow-next; fast fast-next-next; } ListNode *prev nullptr; while(slow){ ListNode *next slow-next; slow-next prev; prev slow; slow next; } while(prev){ if(head-val ! prev-val) return false; head head-next; prev prev-next; } return true; }练习题11验证回文串忽略非字母数字字符后判断回文。练习题12最短无序连续子数组找出需要排序的最短子数组使整个数组升序。双指针优化策略接雨水问题通过左右最大值指针计算积水量。int trap(vectorint height) { int left 0, right height.size() - 1; int left_max 0, right_max 0; int res 0; while(left right){ if(height[left] height[right]){ height[left] left_max ? left_max height[left] : res left_max - height[left]; left; } else { height[right] right_max ? right_max height[right] : res right_max - height[right]; right--; } } return res; }练习题13最大连续1的个数III最多翻转K个0后的最大连续1长度。练习题14水果成篮收集两种水果的最大总量滑动窗口变种。指针操作技巧链表排序结合归并排序和快慢指针分割链表。ListNode* sortList(ListNode* head) { if(!head || !head-next) return head; ListNode *slow head, *fast head-next; while(fast fast-next){ slow slow-next; fast fast-next-next; } ListNode *mid slow-next; slow-next nullptr; return merge(sortList(head), sortList(mid)); } ListNode* merge(ListNode* l1, ListNode* l2) { ListNode dummy(0); ListNode *tail dummy; while(l1 l2){ if(l1-val l2-val){ tail-next l1; l1 l1-next; } else { tail-next l2; l2 l2-next; } tail tail-next; } tail-next l1 ? l1 : l2; return dummy.next; }练习题15奇偶链表将所有奇数节点和偶数节点分别排在一起。练习题16重排链表L0→Ln→L1→Ln-1→...形式重新排列。边界条件处理颜色分类荷兰国旗问题三指针分区处理。void sortColors(vectorint nums) { int low 0, high nums.size() - 1, mid 0; while(mid high){ if(nums[mid] 0){ swap(nums[low], nums[mid]); } else if(nums[mid] 1){ mid; } else { swap(nums[mid], nums[high--]); } } }练习题17移动零将所有0移动到数组末尾。练习题18区间列表的交集给定两个区间列表返回它们的交集。综合应用实例最长山脉数组使用双向遍历寻找山脉峰值。int longestMountain(vectorint arr) { int n arr.size(), res 0; vectorint up(n, 0), down(n, 0); for(int i n-2; i 0; --i){ if(arr[i] arr[i1]) down[i] down[i1] 1; } for(int i 1; i n; i){ if(arr[i] arr[i-1]) up[i] up[i-1] 1; if(up[i] down[i]) res max(res, up[i] down[i] 1); } return res 3 ? res : 0; }练习题19数组中的最长湍流子数组比较符号交替的最大子数组长度。练习题20统计优美子数组恰好包含k个奇数的子数组数目。