Container With Most Water
Given n non-negative integers a1, a2, …, an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container.
tag:
9/26/2015 update
class Solution { public: int maxArea(vector<int>& height) { if(height.size() < 2) return 0; int i = 0; int j = height.size() - 1; int ans = 0; while(i < j){ int thisAns = min(height[i], height[j]) * (j - i); ans = ans < thisAns? thisAns: ans; if(height[i] < height[j]){ i++; } else{ j--; } } return ans; } };
暴力搜,o(n^2)超时。
class Solution { public: int maxArea(vector<int> &height) { int maxCapacity = 0; for(vector<int>::iterator start = height.begin(); start != height.end(); start++){ for(vector<int>::iterator end = start + 1; end != height.end(); end++){ int minHeight = min(*start, *end); int thisCapacity = minHeight * distance(start, end); if (thisCapacity > maxCapacity){ maxCapacity = thisCapacity; } } } return maxCapacity; } };
先排序,然后剪枝。最坏情况o(n^2),不幸test case中有最坏情况(1, 2, 3, 4, 5, 6…)超时。
class point{ public: int height; int x; point(int x, int h) : x(x), height(h){} }; class Cmp{ public: bool operator()(point a, point b){ return a.x > b.x; } }; class Solution { public: int maxArea(vector<int> &height) { int maxCapacity = 0; vector<point> data; for(int i = 0; i < height.size(); i++){ data.push_back(point(i, height[i])); } sort(data.begin(), data.end(), Cmp()); for(vector<point>::iterator start = data.begin(); start != data.end(); start++){ if((*start).height * max((int)(data.size() - (*start).x - 1), (*start).x) < maxCapacity){ return maxCapacity; } for(vector<point>::iterator end = start + 1; end != data.end(); end++){ if((*end).height * max((int)(data.size() - (*end).x - 1), (*end).x) < maxCapacity){ break; } int minHeight = min((*start).height, (*end).height); int thisCapacity = minHeight * distance(start, end); if (thisCapacity > maxCapacity){ maxCapacity = thisCapacity; } } } return maxCapacity; } };
再次优化,这题和直方图中最大矩形的那道题很类似。
我用left储存原数组中左到右递增的序列,用right储存原数组中从右到左递增的序列。在两个数组中遍历。
最坏情况o(n^2)。AC了。
class node{ public: int x; int height; node(int x, int h): x(x), height(h){} }; class Solution { public: int maxArea(vector<int> &height) { int maxCapacity = 0; vector<node > left; vector<node > right; int length = height.size(); left.push_back(node(0, height[0])); right.push_back(node(length - 1, height[length - 1])); for(int i = 0; i < length; i++){ if(left.back().height < height[i]){ left.push_back(node(i, height[i])); } if(right.back().height < height[length - i - 1]){ right.push_back(node(length - i - 1, height[length - i - 1])); } } for(int i = 0; i < left.size(); i++){ int idxl = left[i].x; for(int j = 0; j < right.size(); j++){ int idxr = right[j].x; if(idxr <= idxl){ break; } int thisCapacity = min(left[i].height, right[j].height) * (idxr - idxl); if(thisCapacity > maxCapacity){ maxCapacity = thisCapacity; } } } return maxCapacity; } };
但是看了解答,其实有更好的o(n)的方法。
维护两个指针,一个放在数组开头,一个放在数组末尾。
两个指针都向中间靠拢,每次移动height小的那个指针。因为height小的是影响盛水量的瓶颈。
class Solution { public: int maxArea(vector<int> &height) { int maxCapacity = 0; int start = 0; int end = height.size() - 1; while(start < end){ int minHeight = min(height[start], height[end]); int thisCapacity = minHeight * (end - start); if (thisCapacity > maxCapacity){ maxCapacity = thisCapacity; } if(minHeight == height[start]){ start++; } else{ end--; } } return maxCapacity; } };