博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
接水问题-盛最多水的容器与接雨水问题
阅读量:5363 次
发布时间:2019-06-15

本文共 2717 字,大约阅读时间需要 9 分钟。

近期在做题的时候,有两道题目比较有启发。

题目来源:LeetCode

:给定 n 个非负整数 a1a2,...,an,每个数代表坐标中的一个点 (iai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (iai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

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

在做“盛水最多的容器”时,最开始的想法是动态规划,寻找转移方程。但是思索了很久没有想到后一个状态与前一个状态的联系。后来看了解析之后,发现了一种新的看待问题和寻找最优解的思路。

在做这题时,使用双指针,一个指向最左,一个指向最右,维护一个当前的最大值。

思路重点:将两个指针中较小的那一个往中间移动。

背后原理:当前已经有了一个最大值了,可以看做是当前信息条件下的最优。而能够优化这个问题的办法就是将限制当前值的条件进行改变,尝试寻找更优的解法。即,将较小的指针往中间移动。

在其他问题中,也可以通过这种方式寻找思路:找到一个部分最优解,通过优化当前的短板,进而优化整个问题。

class Solution {    public int getArea(int[] height, int start, int end)    {        return Math.min(height[start], height[end])*(end-start);    }    public int maxArea(int[] height) {        int n = height.length;        int start = 0, end = n-1;        int max_area = 0;        while (start!=end)        {            int temp_area = getArea(height, start, end);            max_area = Math.max(max_area, temp_area);            if (height[start] > height[end])                end--;            else                start++;        }        return max_area;    }}

 

接雨水问题相对更加复杂。最一开始我的想法整个是错误的:从左向右找“坑”,然后找到一个坑就计算这个坑能接多少,最后加起来。但是这种想法的问题在于没有想到可能有更大的坑包住了这些小坑,根本原因在于局部小坑的边界可能并不是盛水的边界,而可能被包着它的更大的坑漫过。

而这个问题实际的想法是:找到所有柱子里的最大值。这样,最大值这个柱子就不可能被其他的更大的坑漫过。由此,分为了左右两个部分,从左和从右分别向最大值靠近即可。

class Solution {        public int trap(int[] height) {        if (height == null || height.length <3)            return 0;        int pos=0, highest = 0, n = height.length;        for (int i = 0; i < n; ++i)        {            if (height[i] > highest)            {                highest = height[i];                pos = i;            }        }        int temp = height[0], result = 0;        for (int i = 0; i < pos; ++i)        {            if (height[i] < temp)                result += (temp - height[i]);            else                temp = height[i];        }        temp = height[n-1];        for (int i = n-1; i >= pos; --i)        {            if (height[i] < temp)                result += (temp-height[i]);            else                temp = height[i];        }        return result;    }}
View Code

而另一个更近一步的做法是结合前一题的想法,不用第一次先遍历找到最大值,再左右向中间靠近。而可以左右两个指针,谁小向中间移动谁。这样做实际上相当于在这一次遍历的过程中,既找了最大值,又计算了水量。

class Solution {public:    int trap(vector
& height) { int result = 0; for (int i = 0, j = height.size() - 1, left_max = 0, right_max = 0; i < j; ) { if (height[i] > left_max) left_max = height[i]; if (height[j] > right_max) right_max = height[j]; if (left_max <= right_max) result += left_max - height[i++]; else result += right_max - height[j--]; } return result; }};

 

转载于:https://www.cnblogs.com/mockingbirdbad/p/10568337.html

你可能感兴趣的文章
双重标准,我该怎么解决
查看>>
python中的网页标签等字符处理
查看>>
Linux常用命令(五)
查看>>
Linux常用命令(四)
查看>>
Linux常用命令(六)
查看>>
Linux常用命令(八)
查看>>
Linux常用命令(七)
查看>>
Linux常用命令(九)
查看>>
Linux常用命令(十一)
查看>>
Linux常用命令(十)
查看>>
实验吧之这就是一个坑
查看>>
Linux常用命令(十二)
查看>>
Linux常用命令(十五)
查看>>
Linux常用命令(十四)
查看>>
Linux常用命令(十七)
查看>>
Linux常用命令(十六)
查看>>
Linux常用命令(二十四)
查看>>
4种java定时器
查看>>
Vue.js 教程
查看>>
linux 设置网卡
查看>>