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 and n is at least 2.
给定一个数组,求出能够包含容量最大的一个矩形区域的起始坐标。
假定矩形区域的左右短点为i,j 则矩形区域的面积 min(height[i], height[j]) *(j-i) (i<j)
笨办法遍历所有情况: 时间复杂度N2
def maxArea(height=[1,8,6,2,5,4,8,3,7]):
"""
:type height: List[int]
:rtype: int
"""
r = 0
for i in range(0,len(height)-1):
for j in range(i+1,len(height)):
print(i, j, (min(i,j))*(j-i))
r = max(r, min(height[i],height[j])*(j-i))
print(r)
return r
利用双指针,分别从左右端点进行遍历求解,矩形区域的面积与端点距离以及端点值的最小值决定,初始化i=0 j=len-1,此时端点距离最大,而min(height[i],height[j])未必是所有情况最大的,现在开始搜索下一种情况可能会比初始值更大的情况,i增加,j减少时,端点距离减少,但是最小值可能会增加,因此矩形面积可能也会增加。
s = min(height[i], height[j]) *(j-i) (i<j) 当i,j由初始情况变化时,j-i必定会减少,现在要使s增大,则要使min(height[i], height[j])变大,显然其值由较小值决定,因此应该移动较小值来试探下一个可能的s较大值。
def maxArea2(height=[1,8,6,2,5,4,8,3,7]):
"""
:type height: List[int]
:rtype: int
"""
i = 0
j = len(height)-1
r = 0
while i<j:
r = max(r, min(height[i],height[j])*(j-i))
if height[i]<height[j]:
i += 1
else:
j -= 1
print(r)
return r
下面是大神的解释:
假定数组元素共有6个,则i,j的取值一共有36中组合情况,其中i==j为零不需要计算 i>j与i<j是对称的,因此只需要计算一半即可。构建一个矩阵,行表示左指针i的取值,列表示右指针j的取值: x表示不需要计算 o表示最优值的探索路径 ---表示可以直接跳过的取值集合,要求最优值,即遍历所有i,j取值组合,利用s = min(height[i], height[j]) *(j-i) (i<j) 求出最大值即可。一般情况遍历所有取值组合需要N2复杂度,现在要利用左右端点较小值,来优化搜索路径:
初始情况,i<j 即只需要搜索所有对角线右上组合即可,初始时(1,6)此时若左端点值小于右端点值,则(1,2:5)则不需要搜索,因为此时容量由较小值左端点决定,移动右端点并不能优化最大值
当height[i]<height[j]时,执行i++ 搜索位置(2,6) 若此时右端点小于左端点,移动左端点并不能增大面积,因此(3:5,6)可以不用搜索
height[j]<height[i]时,j--
依次遍历,最终结果相当于搜索i,j所有取值组合,即一定可以搜索到最优值,并且时间复杂度为O(N).