LeetCode11 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.
分析:
自己做的时候脑子并不是很清楚(帮老板画图画的...),不过一步一步优化也算AC了。但是看着跑的时间那么高就知道肯定不是最优,
学习讨论区后知道了O(n)算法的思路并实现,思考历程记录如下:
1.暴力先写一个,把所有区间来一遍,O(n^2)。当然肯定超时...代码还是记录一下吧
1 class Solution { 2 public: 3 int maxArea(vector<int>& height) { 4 int result = 0; 5 for (int i = 1; i < height.size(); ++i) { 6 for (int j = 0; j < i; ++j) { 7 int h = i - j; 8 int l = min (height[i], height[j]); 9 result = max(result, h * l); 10 } 11 } 12 return result; 13 } 14 };
2. 不按照区间走,按照不同高度,高度依次向上时,找到符合该高度的最长区间(两头扫),然后比较。
高度用个map存,代码如下:(分析时间复杂度O(m*n*logm) m不同高度的数量),诸如1,2,3...15000全是不同高度数字的样例也会超时
class Solution { public: int maxArea(vector<int>& height) { set<int> s; for (int i = 0; i < height.size(); ++i) { s.insert(height[i]); } auto itr = s.begin(); int result = (*itr) * (height.size() - 1); for ( itr = s.begin(); itr != s.end(); ++itr) { int left = 0, right = height.size() - 1; while (height[left] < (*itr) ) { ++left; } while (height[right] < (*itr) ) { --right; } result = max(result, (right - left) * (*itr) ); } return result; } };
3.分析上述代码,其实left,right这里根本没必要每次都从头遍历。因为height是递增的,所以left,right在上一次基础上继续走即可。
所以代码内层只需一遍遍历,复杂度O(m*logm),这个可以AC了。
1 class Solution { 2 public: 3 int maxArea(vector<int>& height) { 4 set<int> s; 5 for (int i = 0; i < height.size(); ++i) { 6 s.insert(height[i]); 7 } 8 auto itr = s.begin(); 9 int result = 0; 10 int left = 0, right = height.size() - 1; //这句优化! 11 for (itr = s.begin(); itr != s.end(); ++itr) { 12 while (height[left] < (*itr) ) { 13 ++left; 14 } 15 while (height[right] < (*itr) ) { 16 --right; 17 } 18 result = max(result, (right - left) * (*itr) ); 19 } 20 return result; 21 } 22 };
4.实际上,也没有必要按照高度存储和遍历。
注意到如果从最大长度区间开始向内遍历,只有当高度更高时才有可能更新面积(因为长度已经比之前小),所以,两根指针一遍遍历即可。O(n)
代码:
1 class Solution { 2 public: 3 int maxArea(vector<int>& height) { 4 int i = 0, j = height.size() - 1, result = 0; 5 while (i < j) { 6 int minHeight = min(height[i], height[j]); 7 result = max(result, minHeight * (j - i)); 8 while (height[i] <= minHeight) { 9 i++; 10 } 11 while (height[j] <= minHeight) { 12 j--; 13 } 14 } 15 return result; 16 } 17 };