zoukankan      html  css  js  c++  java
  • 思维题(两点逼近)LeetCode11 Container with Most Water

    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.

    给定n条线段,每条线段的端点为(i,0)和(i,a[i]),现在需要在这n条线段中选择两条并与x轴组成一个水桶,求最大容量的水桶的容量(面积)。

    暴力的方法就是直接枚举两条线段,找最大面积,这样复杂度是O(n^2)的。(没想到leetOJ居然还有稍强的数据,感觉是故意卡死这个复杂度的方法的。。)

    我换了一个思路后,想到由于最后的最大面积一定是以某一个线段为桶的一侧(可能是左侧或者右侧)并且刚好淹没这条线段,那我们只需要枚举每条线段,然后找出这条线段左侧(或者右侧)比它高的最左(最右)的一个线段的位置,然后计算面积,并记录最大面积即可。

    找到左侧比当前线段要高的最左侧线段的方法,可以直接将每个线段先按高度从大到小,再按坐标从小到大排序,然后扫描数组,记录 到当前的最小坐标,由于后扫描到的线段高度一定比先扫描到的高度小,所以只需要记录前面的坐标的最小值,便是当前线段的最左侧线段的坐标。时间复杂度O(nlogn)空间O(n)。

    官网给出的标准方法,由于智力有限并不能想到,但是对其正确性还是可以给出证明。方法如下:

    令指针i,j指向数组的开头和结尾,然后每次选取height[i]和height[j]较小的那个指针,并将指针想中间位置移动以为,并重新计算面积。(时间复杂度O(n),空间复杂度O(1))。

    虽然我不能对这个方法有比较好的启发式的思维来想到,但是我至少还是得对其正确性给出证明,我的方法如下:

    令a(i,j)表示线段i和j组成的面积(即a(i,j)=(j - i) * min{height(i), height(j)}),令DP(i,j)表示区间[i,j]的最大答案,则有:

    DP(i,j) = max{DP(i+1,j), DP(i, j-1), a(i, j)}

    只要证明当height(i) <= height(j)时,DP(i,j) = max{DP(i+1,j),a(i,j)}恒成立即可。

    证明过程只需要分情况讨论即可:

    1、若a(i,j) == DP(i,j) 这时结论显然成立。

    2、若a(i,j) < DP(i,j) 

            1) 若DP(i+1, j-1) == DP(i,j)  这时,由于DP(i+1,j) >= DP(i+1, j-1),这时结论成立。

            2) 若DP(i+1, j-1) < DP(i,j)  这时有DP(i,j) = max{DP(i+1,j), DP(i, j-1)}

                因为DP(i + 1,j) = max{DP(i+1,j-1), a(i+1,j), a(i+2, j), ... , a(j - 1, j), a(j, j)}

                同时DP(i, j - 1) = max{DP(i+1,j-1), a(i, i), a(i,i+1), a(i, i+2), ... , a(i, j - 1)}

                因为height(i) <= height(j) 所以有max{a(i, i), a(i,i+1), a(i, i+2), ... , a(i, j - 1)} <= a(i, j) < DP(i, j)恒成立。

                所以 DP(i, j) = DP(i+1, j)。得证。

     1 public class Solution {
     2     public int maxArea(int[] height) {
     3         int maxarea = 0, l = 0, r = height.length - 1;
     4         while (l < r) {
     5             maxarea = Math.max(maxarea, Math.min(height[l], height[r]) * (r - l));
     6             if (height[l] < height[r])
     7                 l++;
     8             else
     9                 r--;
    10         }
    11         return maxarea;
    12     }
    13 }
  • 相关阅读:
    SparkSql初级编程实践
    云时代架构之苏宁安全架构演进及实践
    云时代架构之知乎网站架构变迁史
    质量属性的六个常见属性场景之《淘宝网》
    云时代架构之游戏服务器的架构演进
    《架构漫谈阅读心得》
    转换后缀表达式
    约瑟夫环(改进3.0)
    栈结构之后缀表达式
    约瑟夫环(改进2.0)
  • 原文地址:https://www.cnblogs.com/gj-Acit/p/5845552.html
Copyright © 2011-2022 走看看