10.12ContainerWithMostWater - WisperDin/blog GitHub Wiki

desc

Given n non-negative integers a1a2, ..., *an *, where each represents a point at coordinate (iai). n vertical lines are drawn such that the two endpoints of line i is at (iai) 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.

The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.

 

Example:

Input: [1,8,6,2,5,4,8,3,7]
Output: 49

思路

根据公式 area = min(h(t2),h(t1)) * (t2-t1)

以下简化为 area = min * dist

t 为数组的索引, h(t) 为对应索引处的值

  • 暴力 O(N^2) 枚举所有可能,计算最大的area
  • 排除法, O(N) 通过式子的特性,尽可能的排除不需要计算的对象 leetcode上解释

leetcode上面已经说的很详细了,对

[1,8,6,2,5,4,8,3,7]
 0 1 2 3 4 5 6 7 8
 
从左右两边向中间收缩,寻找最大值
1. h(0)<h(8) 此是 area = 1 * (8-0)  此时min = 1 , dist = 8 
!! 对于 0 位置来说,可以排除的结果对 0-1 0-2 0-3 ... 0-7
为什么呢? 因为 0-1 ... 0-7 其中 min <= 1 且 dist < 8 
所以这些结果对的值永远不会大于 0 - 8

根据这种方法收缩,可以在排除很多结果对的情况下,在O(N)情况下找到最大的area

实现

func maxArea(height []int) int {
    if len(height)<2{
        return -1
    }
    
    l := 0
    r := len(height)-1 
    area := 0
    for l<r {
        tmpMax := 0
        if height[l]<height[r] {
            tmpMax = height[l] * (r-l)
            l++
        }else {
            tmpMax = height[r] * (r-l)
            r--
        }
        if tmpMax > area {
            area = tmpMax
        }
    }
    return area
}

总结

对于公式,可以制造条件将其中某个变量控制到从某个特殊值开始,再在这个条件下单独研究另一个变量

在这个题目下,制造了从两端开始收缩的环境,使得 dist 变量 从最大开始,则对于两端内的其他结果对,其 dist 必定更小,再研究min变量,对于当前结果对的最小元素 (设为M) 来所,这个元素与两端内 的任意元素组成一对,其min<=M

结论: 排除当前两端内,与当前最小元素组成的结果对(实现来说,就直接跳过该最小元素,继续收缩)

(这些结果对被排除的原因):

  • dist 更小
  • min <= M