zoukankan      html  css  js  c++  java
  • Leetcode: 43. 接雨水

    题目描述:

    给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

     

    上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。

    示例:

    输入: [0,1,0,2,1,0,1,3,2,1,2,1]
    输出: 6

    思路分析:

    思路一:这是一个类似木桶效应的问题。比较多的思路是利用单调栈来实现。之前大四上算法课的时候也做过类似的题目。维护一个单调递减的栈,当遇到大于当前栈顶的高度时,出栈,计算可接多少水,算法是取现在的栈顶元素与待进栈元素的较小高度减去这个出栈元素的高度,再乘上待进栈元素与栈顶元素的宽度。这里注意维护在栈内的元素时对应的下标,以保证能够求得正确的宽度。这个方法是逐层求可接雨水。时间复杂度为O(n^2)。

    思路二:

    在实际的面试过程中,肯定是希望能够优化这个算法,考虑用双指针,逐列的来取雨水。维护左右两个指针left和right,分别指向数组的头尾,同时维护两个数值,存maxleft和maxright,即当前遍历过的所有左右元素的最大高度。需要进行判断,若left的高度小于right的高度,则left++,否则right--。同时在每次判断是还需要多一次判断,即是否能够加水,需要判断当left小于right时,left是否小于maxleft,若是,那么就可以加水,所加的水为maxleft-height[left]。反之,当right小于等于left的高度时,添加maxright-height[right]的水量。这个方法的时间复杂度为O(n)。

    代码:

    思路一:

     1 class Solution {
     2 public:
     3     
     4     int trap(vector<int>& height) {
     5         if(height.size()==0)
     6             return 0;
     7         int sum_rain = 0;
     8         stack<int> s;
     9         for(int i=0; i<height.size(); i++)
    10         {
    11             if(s.empty() || height[i]<height[s.top()])
    12                 s.push(i);
    13             else
    14             {
    15                 while(!s.empty() && height[i]>height[s.top()])
    16                 {
    17                     int pre = s.top();
    18                     s.pop();
    19                     if(!s.empty())
    20                     {
    21                         sum_rain += (min(height[i], height[s.top()])-height[pre])*(i-s.top()-1);
    22                     }
    23                 }
    24                 s.push(i);
    25             }
    26         }
    27         return sum_rain;
    28     }
    29 };

    思路二:

     1 class Solution {
     2 public:
     3     int trap(vector<int>& height) {
     4         if(height.size()==0)
     5             return 0;
     6         int sum_rain = 0;
     7         int left=0, right = height.size()-1;
     8         int leftmax=0, rightmax=0;
     9         while(left<right)
    10         {
    11             if(height[left]<height[right])
    12             {
    13                 if(height[left]<leftmax)
    14                 {
    15                     sum_rain += (leftmax-height[left]);
    16                 }
    17                 else
    18                     leftmax = height[left];
    19                 left++;
    20             }
    21             else
    22             {
    23                 if(height[right]<rightmax)
    24                 {
    25                     sum_rain += (rightmax-height[right]);
    26                 }
    27                 else
    28                     rightmax = height[right];
    29                 right--;
    30                     
    31             }
    32             
    33         }
    34         return sum_rain;
    35     }
    36 };
  • 相关阅读:
    单词方阵【DFS】
    关于vs扩展下载慢的问题。(更改一下,补充)
    归并排序的应用
    用qt做了个简易音乐播放器(零基础真的是太难了)
    实操理解微软所说的“物理文件位置”和“逻辑文件位置”的区别
    获取指定数量的容器的各自的所有元素,并可对容器分页
    [备忘]silverlight中关于“复制到输出目录”和“生成操作”
    [备忘]silverlight中播放视频路径问题
    与并行相关的常见概念
    巧用vs的PostBuildEvent
  • 原文地址:https://www.cnblogs.com/LJ-LJ/p/11166690.html
Copyright © 2011-2022 走看看