1 题目描述
给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例:
输入: [1,8,6,2,5,4,8,3,7] 输出: 49
2 解题思路
2.1 暴力解析(结果正确但超时不通过)
最简单的就是暴力解析,时间复杂度N*N
static const auto io_sync_off = []() { // turn off sync std::ios::sync_with_stdio(false); // untie in/out streams std::cin.tie(nullptr); return nullptr; }(); class Solution { public: int maxArea(vector<int>& height) { int maxCap = 0; for (int i = 0; i < height.size() - 1; ++i) { for (int j = i + 1; j < height.size(); ++j) { int cap = (height[i] < height[j] ? height[i] : height[j]) * (j - i); if (cap > maxCap) { maxCap = cap; } } } return maxCap; } };
2.2 一趟归纳(效率最高)
怎么在时间复杂度为N的情况下算出结果?我刚开始也想不到,看了别人的答案才明白的。思路是这样的:
(1)类似于快排的思路,两个游标分别从两段进行判断;
(2)比较两个游标位置大小,两者之间的“容量”是以较矮的一个值为准,计算出此时的容量与MAX值比对;
(3)要想获得可能更大的容量,肯定是要游动较矮的游标,企图找到一个更高一些的组成新的容器;
(4)迭代到两个游标相遇就结束了。
static const auto io_sync_off = []() { // turn off sync std::ios::sync_with_stdio(false); // untie in/out streams std::cin.tie(nullptr); return nullptr; }(); class Solution { public: int maxArea(vector<int>& height) { int max = 0; for (int i = 0, j = height.size() - 1; i < j; ) { int minHeight = height[i] < height[j] ? height[i++] : height[j--]; max = max > ((j - i + 1) * minHeight) ? max : ((j - i + 1) * minHeight); } return max; } };