算法学习解题技巧-对撞指针-LeetCode11

359 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

在昨天学习的算法解题技巧之一: 二分法 利用的就是 双指针. 今天具体来学习一个进阶问题: 盛水问题.

双指针

双指针 顾名思义, 就是有两个指针 指向两个位置(坐标元素).

对比单指针: 比方说要迭代一个数组, 输出数组中的每一个元素, 这时只需要一个指针(下标 i)来记录当前输出的元素, 这个过程就是单指针.

双指针就是有两个这样的下标. 最经典的就是昨天(上文)学习用到的左/右(一前一后)双指针.

盛水问题

LeetCode 11: 先看图吧, 比较好理解, 但是解决问题就没有昨天那个问题那么简单了. LeetCode 定义为 中等.

image

题目描述:

给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点  (i, ai) 。在坐标内画 n 条垂直线,垂直线 i  的两个端点分别为  (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与  x  轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器, 且 n 的值最少为 2 就得组成容器。

解题思路分析:

两条直线间盛水的多少取决于 两个部分:

  1. 两个直线间的距离, 即两个下标的差值
  2. 两个线中间低的那个

这里比方说定义两个指针表示两个坐标, 则盛水量可表示为: min(height[i], height[j]) * (j - i)

1. 直接暴力解法:

直接找出能盛水的全部可能性. 然后找到其中的最大值. 但是这个方法同样会超时!

暴力解法复杂度:

  • 时间复制度: O(n^2), 找出全部可能性即对每一对进行查找计算, 共计算 n*(n-1)/2
  • 空间复杂度: O(1), 只需要表示最大面积的一个额外变量

2. 双指针法:

  • 先看下执行时间 及结果

image

  • 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)

思考

这两次学习的 对撞指针法 都是从 两端 开始的, 当然也有从开始的 快慢指针法, 后面会慢慢来学习.