• 42.Trapping Rain Water---dp,stack,两指针


    题目链接:https://leetcode.com/problems/trapping-rain-water/description/

    题目大意:与84题做比较,在直方图中计算其蓄水能力。例子如下:

    法一(借鉴):暴力,还是很难想到的,需要推理数学功底。因为这里暴力的前提条件是:计算每个点的蓄水能力,相当于求解,min(每个点左边的最大高度,每个点右边的最大高度)-当前值。也就是这里,把一整个蓄水池的分解成一个点一个点的蓄水能力。代码如下(耗时150ms):

     1     public int trap(int[] height) {
     2         int res = 0;
     3         for(int i = 0; i < height.length; i++) {
     4             int left = height[i], right = height[i];
     5             //找左边最大高度
     6             for(int j = i - 1; j >= 0; j--) {
     7                 left = Math.max(left, height[j]);
     8             }
     9             //找右边最大高度
    10             for(int j = i + 1; j < height.length; j++) {
    11                 right = Math.max(right, height[j]);
    12             }
    13             //计算蓄水
    14             res += Math.min(left, right) - height[i];
    15         }
    16         return res;
    17     }
    View Code

    法二(借鉴):一维dp,思想与上面暴力相同,都是取左右两边高度的较小者然后与当前值比较,如果大,则可以蓄水。代码如下(耗时22ms):

     1     public int trap(int[] height) {
     2         int dp[] = new int[height.length];
     3         int ma = 0, res = 0;
     4         //记录i值左边的最大高度
     5         for(int i = 0; i < height.length; i++) {
     6             dp[i] = ma;
     7             //更新左边最大高度
     8             ma = Math.max(ma, height[i]);
     9         }
    10         //更新计算i值右边的最大高度
    11         ma = 0;
    12         for(int i = height.length - 1; i >= 0; i--) {
    13             //在左边和右边最大高度中取较小者
    14             dp[i] = Math.min(dp[i], ma);
    15             //更新右边
    16             ma = Math.max(ma, height[i]);
    17             //如果两边高度比当前高度高,则表示可以蓄水
    18             if(dp[i] > height[i]) {
    19                 res += dp[i] - height[i];
    20             }
    21         }
    22         return res;
    23     }
    View Code

    法三(借鉴):stack,与84题stack做法比较,此题在压栈的时候是降序高度压栈,当当前高度>s.peek()时,可以蓄水,栈顶第一个元素为坑最低高度,栈顶第二个元素为左边界,当前高度为右边界,坑深为min(左高度,右高度)-坑最低高度。代码如下(耗时30ms):

     1     //入栈递减高度,当当前高度>s.peek()时,可以蓄水,栈顶第一个元素为坑最低高度,栈顶第二个元素为左边界,当前高度为右边界,坑深为min(左高度,右高度)-坑最低高度
     2     public int trap(int[] height) {
     3         Stack<Integer> s = new Stack<Integer>();
     4         int res = 0;
     5         for(int i = 0; i < height.length; i++) {
     6             //循环查找在当前高度下,是否可以蓄水
     7             while(!s.isEmpty() && height[i] > height[s.peek()]) {
     8                 int cur = s.pop();
     9                 //如果栈空,说明没有左边界,没法蓄水,所以直接break
    10                 if(s.isEmpty()) {
    11                     break;
    12                 }
    13                 //计算蓄水,此时不再是按照前面的方法,分点计算竖状蓄水能力,而是按照整块的蓄水能力计算的,也就是普通思维的按照蓄水池的长*宽来计算的
    14                 res += (i - s.peek() - 1) * (Math.min(height[s.peek()], height[i]) - height[cur]);
    15             }
    16             //如果比栈顶高度小,压栈
    17             s.push(i);
    18         }
    19         return res;
    20     }
    View Code

     法四(借鉴):两个指针移动,比较左指针指向的高度和右指针指向的高度,记录较小者,如果左指针指向的较小,则从左往右遍历,如果右指针指向的较小,则从右往左遍历,如果遍历到的当前值比较小者小,则表示可以蓄水:较小者-当前值。代码如下(22ms):

     1     //定义两个指针,左指针与右指针的值进行比较,记录较小者,如果左指针较小,则从左往右遍历,如果右指针较小,则从右往左遍历,如果遍历到的值比较小者小,则表示可以蓄水:较小者-当前值
     2     public int trap(int[] height) {
     3         int left = 0, right = height.length - 1, mi = 0, res = 0;
     4         while(left < right) {
     5             //如果左指针较小,从左往右遍历
     6             if(height[left] < height[right]) {
     7                 mi = height[left++];
     8                 while(left < right && height[left] < mi) {
     9                     res += mi - height[left++];
    10                 }
    11             }
    12             //如果右指针较小,从右往左遍历
    13             else {
    14                 mi = height[right--];
    15                 while(left < right && height[right] < mi) {
    16                     res += mi - height[right--];
    17                 }
    18             }
    19         }
    20         return res;
    21     }
    View Code
  • 相关阅读:
    c#发送邮件.net1.1和.net2.0中的两个方法
    六步使用ICallbackEventHandler实现无刷新回调
    报表项目总结
    转载:Tomcat Port 8009 与AJP13协议
    JUnit4 使用指南二 (熟练掌握)
    JUnit4 使用指南一 (简单上手)
    HP的项目中曾做一个业务日志系统
    Unitils使用(转载)
    iBatis 学习
    JUnit4 使用指南三 (Runner 特性分析)
  • 原文地址:https://www.cnblogs.com/cing/p/8494152.html
Copyright © 2020-2023  润新知