小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
在昨天学习的算法解题技巧之一: 二分法 利用的就是 双指针. 今天具体来学习一个进阶问题: 盛水问题.
双指针
双指针 顾名思义, 就是有两个指针 指向两个位置(坐标元素).
对比单指针: 比方说要迭代一个数组, 输出数组中的每一个元素, 这时只需要一个指针(下标 i)来记录当前输出的元素, 这个过程就是单指针.
那 双指针就是有两个这样的下标. 最经典的就是昨天(上文)学习用到的左/右(一前一后)双指针.
盛水问题
LeetCode 11: 先看图吧, 比较好理解, 但是解决问题就没有昨天那个问题那么简单了. LeetCode 定义为 中等.
题目描述:
给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器, 且 n 的值最少为 2 就得组成容器。
解题思路分析:
两条直线间盛水的多少取决于 两个部分:
- 两个直线间的距离, 即两个下标的差值
- 两个线中间低的那个
这里比方说定义两个指针表示两个坐标, 则盛水量可表示为: min(height[i], height[j]) * (j - i)
1. 直接暴力解法:
直接找出能盛水的全部可能性. 然后找到其中的最大值. 但是这个方法同样会超时!
暴力解法复杂度:
- 时间复制度:
O(n^2), 找出全部可能性即对每一对进行查找计算, 共计算n*(n-1)/2 - 空间复杂度:
O(1), 只需要表示最大面积的一个额外变量
2. 双指针法:
- 先看下执行时间 及结果
JavaScript解题代码:
/**
* @param {number[]} height
* @return {number}
*/
var maxArea = function (height) {
let left = 0,
right = height.length - 1,
result = 0
while (left < right) {
const area = Math.min(height[left], height[right]) * (right - left)
result = Math.max(area, result)
if (height[left] <= height[right]) {
left++
} else {
right--
}
}
return result
}
解法复杂度:
- 时间复制度:
O(n) - 空间复杂度:
O(1)
思考
这两次学习的 对撞指针法 都是从 两端 开始的, 当然也有从开始的 快慢指针法, 后面会慢慢来学习.