双指针合集
[1- 移动零](#1- 移动零)
[2- 盛最多水的容器](#2- 盛最多水的容器)
[3- 三数之和](#3- 三数之和)
[4- 接雨水](#4- 接雨水)
1- 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
var moveZeroes = function(nums) {
// 使用快慢指针原地修改数组
// 慢指针记录非0元素放置的位置
let slowIndex = 0
// 快指针遍历数组寻找非0元素
for(let fastIndex = 0 ; fastIndex < nums.length; fastIndex++){
if(nums[fastIndex] !== 0){
// 找到非0元素,将其赋值给慢指针位置
nums[slowIndex] = nums[fastIndex]
slowIndex++
}
}
// 慢指针之后的位置全部赋值为0
for(let i = slowIndex; i < nums.length; i ++){
nums[i] = 0
}
};
2- 盛最多水的容器
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
**说明:**你不能倾斜容器。
var maxArea = function(height) {
// 左右双指针解决经典的"木桶效应"应用
// 左指针初始化为数组最左边
let left = 0
// 右指针初始化为数组最右边
let right = height.length - 1
// 初始化最大储水量为0
let maxArea = 0
while(left < right){
// 计算当前面积
// 高度为左右两根垂线其中更矮的
let h = Math.min(height[left],height[right])
// 宽度为两根垂线之间的距离
let w = right - left
// 计算当前两根垂线组成的面积
let currentArea = h * w
// 更新最大面积
maxArea = Math.max(currentArea,maxArea)
// 指针移动逻辑
// 总是移动垂线短的那一侧的指针
if(height[left] < height[right]){
left++
}else{
right--
}
}
return maxArea
};
3- 三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
**注意:**答案中不可以包含重复的三元组。
var threeSum = function(nums) {
// 排序 + 双指针
// 固定一个数找另外两个数
// 对第一个数的去重 && 对第二个和第三个数去重
let ans = []
const n = nums.length
// 升序排序
nums.sort((a,b)=>a-b)
for(let i = 0; i < n; i++){
// 当前数值大于0,升序数组,sum一定不为0
if(nums[i] > 0) break;
// 对三元组中的第一个数去重
if(i > 0 && nums[i] === nums[i-1]) continue
// 双指针寻找三元组中另外两个数
let L = i + 1
let R = n - 1
while(L < R){
let sum = nums[i] + nums[L] + nums[R]
// sum=0,符合要求的三元组
if(sum === 0){
// 存储三元组
ans.push([nums[i],nums[L],nums[R]])
// 对第二个数去重
while(L < R && nums[L] === nums[L+1]) L++
// 对第三个数去重
while(L < R && nums[R] === nums[R-1]) R--
// 找到一组答案 两位指针继续向中间收缩
L++
R--
}else if(sum < 0){
// sum太小,需要向右移动(升序数组
L++
}else{
// sum太大,需要向左移动
R--
}
}
}
return ans
};
4- 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
var trap = function(height) {
// 盛水容器的进阶版
let res = 0
let left = 0
let right = height.length - 1
// 初始化左右指针遍历过的韦志中最大的柱子高度,包含当前的left和right
let leftMax = 0
let rightMax = 0
while(left < right){
// 实时更新最大高度
// 先不管柱子能不能盛水,先更新见过的最大高度
leftMax = Math.max(leftMax,height[left])
rightMax = Math.max(rightMax,height[right])
// "木桶效应" 哪边更短结算哪边
if(leftMax < rightMax){
// 当前left位置能够接水的容量:左边最大高度-当前柱子高度
res += leftMax - height[left]
// 左指针右移,处理下一个柱子
left++
}else{
// 当前right位置能接水的容量
res += rightMax - height[right]
// 右指针左移,处理下一个柱子
right--
}
}
return res
};