何为双指针?
双指针算法是一种利用两个指针在数据结构(如数组或链表)上协作遍历的策略。这种算法的核心在于通过两个指针的相对移动来扫描数据,从而达到诸如查找、删除、排序或优化遍历过程等目的。双指针主要分为以下两种常见模式:
1. 快慢指针
- 快的不停移,慢的满足条件才移:【数组去重】【移动0】
(1)去重:[0, slow]范围内去除val
let slow = 0;
for (let fast = 0; fast < nums.length; fast++) { // 快指针不停移动
if (nums[fast] !== val) nums[slow++] = nums[fast]
}
- 快二慢一:【循环链表】
while (fast.next) {
fast = fast.next.next;
slow = slow.next
};
- 快的先移n,然后快慢一起移:【删除链表中的倒数第N个节点】
2. 对撞指针
- 两指针从数组或序列的两端开始,向中间移动,直到它们相遇或超越某个条件。
- 应用:数组中的目标和搜索、查找对称数、数组去重、实现滑动窗口。
模板
function fn(arr) {
let left = 0,right = arr.length - 1;
while(left < right) {
// if( 满足条件 ) {return 结果}
// if( 找到目标 ) {处理逻辑}
if( 偏小 ) left++
else if( 偏大 ) right--
}
}
a. 接雨水
const height = [0,1,0,2,1,0,1,3,2,1,2,1] // 6
解释:图中蓝色区域是6
leftMax, rightMax用来维护 左柱最高值、右柱最高值
while (left < right) {
分别更新 左右两边最高的柱子
左边低?ans += 左边高度差;左移
右边低?ans += 右边高度差;右移
}
b. 盛水最多的容器
const height = [1,8,6,2,5,4,8,3,7] // 49
解释:在8和7两根柱子之间盛水最多=7 * (8-1)
while (left < right) {
当前盛的水 = 左柱和右柱中最短的柱 * (左右柱距离)
更新max
左柱低?左移
右柱低?右移
}
c. 三数之和
const nums = [-1,0,1,2,-1,-4] // [ [ -1, -1, 2 ], [ -1, 0, 1 ] ]
解释:所有可能的三个数字之和为0的组合
* 先排序
* for i 遍历 nums {
* 去重:nums[i]==之前?continue
* while (left < right) {
* if(sum==0){
* ans.push([nums[i], nums[left], nums[right]])
* 左移
* 左移后去重:nums[left] ==之前?左移
* 右移
* 右移后去重:nums[right]==之前?右移
* }else if(小于0) 左移
* else if(大于0) 右移
* }
* }
3. 二分搜索
while (left <= right) {
let mid = Math.floor((left + right) / 2)
if (arr[mid] == target) return mid
else if (arr[mid] < target) left = mid + 1
else right = mid - 1;
}
4. 滑动窗口
- 无重复的最长字串
- 找字符串中所有字母异位词
- 最小覆盖字串
5. 前缀和
// (n)前缀和
// 区间[a,b]的和为sum :表示 map[a] - map[b] = sum
// map[i] = map[i-1] + nums[i]
// map[i+1] = map[i] + nums[i+1]
// curSum = + target
// 区间[j, i] 的和为k :表示 map[i] - map[j] = k