LeetCode:: 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.
题目分析:
1、初看题目是O(N*N)的时间复杂度。输入为N,在N个元素中挑出两个元素,组成的梯形面积来盛水,注意短板效应。所以水量由横向距离W和两板中的短板高度H决定。C(N,2)中种组合,如果全部列举出来求最大值的话,复杂度为N*(N-1)/2。时间复杂度为O(N*N)
2、O(N)的解法,思想非常巧妙。输入为N,下标为0--N-1,输入内容为 Height[0--N-1]。根据水量由W和H决定。要求水量最大,设此区间的起点为begin, 终点为end, 则首先是的W最大,即begin = 0, end = N-1, 此时求得面积 max_area。之后想想,往中间靠的过程,W必定减小,而要使得max_area有可能增大,则只能要求H增大,才有可能。即begin和end中的短板需要得到提升。提升的过程是往中间靠拢的过程。
3、尝试写一段伪代码。其实正确逻辑的伪代码是至关重要的。这会使得之后的编程变得容易许多。思路也清晰。
MaxArea(Height[0--N-1]) { max_area = 0, begin = 0, end = N-1; while(begin < end) { // 当begin >= end 时,重复不必要的计算 max_area = FindMax(前一刻最大,当前最大) // 对begin和end 进行更新 if(Heigt[begin] < Height[end]) begin++; else end--; } }
4、代码很简单,主要在于用这种思路去除了c(n,2)中的很多没有必要判断的情况。最好的情况循环N/2次,最差的情况也只是循环N次。
// 看了参考的思路 // 计算面积需要有两个点的位置。通常的思路是从左边开始往右寻找 // 这个想法,从左右边界同时开始,记录最大值。贪心算法,当左右边界时j-i的值最大 // 向中间靠拢的过程i和j之间的距离变小,要使得面积更大,则要寻找更高的短板。 // 所以从小的一侧往中间搜索,知道i,j相遇,即完成了所有最大值的搜索工作 int Solution::maxArea2(vector<int> &height) { int len = height.size(); if(len < 2) return 0; int begin = 0, end = len-1, max_area = 0; while(begin < end) { // 当begin == end 时,面积为0,不需要计算 max_area = max(max_area, (end-begin)*min(height[begin], height[end])); // 寻找下一个可能的面积 if(height[begin] < height[end]) begin++; else end--; } return max_area; }