php面试题 几升水,twitter面试题之装水问题

这篇文章最初发在CSDN上,现在转到简书,还是比较喜欢简书简约的风格。

据说这是twitter的一个面试题,不过,去年找工作的时候我的一个同学在面试微软的时候也有问到这个问题。很有意思的一个题目,当时我也没有去深究到底怎么实现比较好,几天前在伯乐在线上面看到了这篇文章面试题分析:我的Twitter技术面试失败了, 才知道这个解法原来很简单,只是刚开始没怎么看懂,比较绕。好吧,废话少说,我还是根据自己的理解来说下这个问题,不对之处,还请大家指正。

题目描述

看下面这个图片,在这个图片里我们有不同高度的墙。这个图片由一个整数数组所代表,数组中每个数是墙的高度。上边的图可以表示为数组[2,5,1,2,3,4,7,7,6],假如开始下雨了,那么墙之间的水坑能够装多少水呢?”

a72150138cd7

以1×1的方块为单位计算容积。所以,在上边的图中下标为1以左的都会漏掉。下标7以右的也会漏掉。剩下的只有在1和6之间的一坑水,容积是10。如下图所示。

分析

原文作者最初想法是用极大值考虑,也就是说找到下标2的左右两个极大值,但是这个做法最后作者意识到是错误的。比如下面的情况就不对:

看看这个输入:

a72150138cd7

如果答案计算的是极大值之间的水,就像这样。

a72150138cd7

但是答案应该是在两个高塔之间只有一池水:

a72150138cd7

那其实正确的解法是作者后来灵光一闪想到的,确实看起来很简单。这其实要基于一个事实那就是,你从左往右扫描数组的时候,只要是左边最大值小于右边的数字时,这中间是一定可以存储水的。每次维护一个左墙的最大值,从左向右的扫描过程中遇到大于左边最大值的值,则更新左边最大值,并且不增加存储水的容量,因为在从左往右扫描的过程中,如果遇到的值比左边大,那么存储不了水,如上面例子中从2开始扫描,遇到5的时候,此时存储容量还是0,因为5大于2,这中间存储不了水。从右往左扫描也是一样。

一个基本的解法就是先找到数组最大值,然后从左往右扫描到最大值,计算出水的容量;然后从右往左扫描到最大值,计算出水的容量,最后总的容量就是两部分之和。

描述还是会不怎么清楚,还是以例子来看。以第一个例子[2,5,1,2,3,4,7,7,6]来看,最大值为7,两个7随便选后面一个好了。那么从左往右扫描过程如下:

1)首先设置左边最大值为2,容量设置为0。

2)2小于7,往右继续扫描,遇到5,因为5大于2,所以更新左边最大值为5,此时并不更新存储水的容量,接着往后扫描。

3)扫描到1,因为1比前面的5小,因此现在至少可以存储5-1=4单位水。存储水的容量加4。因为我们知道右边有比左边最大值还大的值,所以肯定是可以至少存储这么多水的。

4)接着扫描到2,还是比5小,存储水的容量增加5-2=3,容量变为4+3=7.

5)继续扫描到3,还是比5小,存储水的容量增加5-3=2,容量变为7+2=9.

6)继续扫描到4,还是比5小,存储水的容量增加5-4=1,容量变为9+1=10.

可以得到左侧存储水的容量为10。同理,从右往左扫描到7,容量为0,因为6小于7,7以右的水全部会漏掉。

那么一个更优的解法其实是只需要扫描一遍就OK,不需要之前扫描数组找最大值,也就是整合了左右扫描的过程。如果左边值小于右边值,则从左往右扫描,否则从右往左扫描。(附python代码在后面)

代码

def calculate(testcase):

p_l = 0

p_r = len(testcase) - 1

max_l = testcase[p_l]

max_r = testcase[p_r]

volume = 0

while p_r > p_l :

if max_l < max_r:

p_l = p_l + 1

if testcase[p_l] >= max_l:

max_l = testcase[p_l]

else:

volume = volume + (max_l - testcase[p_l])

else:

p_r = p_r - 1

if testcase[p_r] >= max_r:

max_r = testcase[p_r]

else:

volume = volume + (max_r - testcase[p_r])

return volume

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值