算法实践——Twitter算法面试题(积水问题)的线性时间解法

问题描述:在下图里我们有不同高度的挡板。这个图片由一个整数数组所代表,数组中每个数是墙的高度。下图可以表示为数组(2、5、1、2、3、4、7、2)。假如开始下雨了,那么挡板之间的水坑能够装多少水(水足够多)呢?

 

下图是装满水的情况,一个蓝色格子代表一个单位的水。下图中一共装了10个单位的水。

 

 

问题分析:

 

先看看下图,判断哪个单元格的水能留下来。下图中的两个单元格,一个红色的单元格和一个绿色的单元格,哪个单元格的水是溜走了,哪个单元格的水能留下来?

很明显的,上图中的红色单元格的水会流走,绿色单元格的水会被留下来。

那么,仔细看看这两个单元格的区别在哪儿

区别就是,红色单元格只有右边的挡板比它高(不低于它),而绿色单元格左右两边都有挡板比它高(左边最高是5,右边最高是7)

这也就很好的理解了,如果水要能留下来,必须左右两边的挡板都比它高才行。(很明显的,不管哪一侧的挡板比水低,水就会朝哪个方向流出去)

 

于是,我给每个挡板定义了3个属性

V属性:本挡板的高度

L属性:本挡板左侧挡板的最高高度

R属性:本挡板右侧挡板的最高高度

 

那么,该挡板上方能积水的充要条件就是:L>V并且R>V

如果该挡板能积水,则积水量为:Min(L-V,R-V)

 

那么总的积水量就是所有挡板的积水量总和

 

问题就变成,如何求出每块挡板的L属性和R属性

用V、L、R三个数组标示挡板组的三个属性。一共有N块挡板,数组的下标从0到N-1。

V(i)表示第i块挡板的高度、L(i)表示第i块挡板的L属性、R(i)表示第i块挡板的R属性

可知的是L(0)=0,R(N-1)=0;

 

不失一般性,考虑第i块挡板的L属性(i>0)。L(i-1)表示第i-1块挡板的L属性。那么,可知

如果L(i-1)>V(i-1),则L(i)=L(i-1)

如果L(i-1)≤V(i-1),则L(i)=V(i-1)

综上所述:L(i)=Max(L(i-1),V(i-1))(i>0)

同理可述:R(i)=Max(R(i+1),V(i+1))(i<N-1)

 

而由于L(0)=0,R(N-1)=0。则说明第0、N块挡板(最左和最右的挡板)是不会积水的

因此,计算L和R的属性以及计算积水量的下标从1开始到N-2即可

 

代码如下:

Public Class clsFillWater
    Public Shared Function FillWater2(ByVal ParamArray Nums() As Integer) As Integer
        Dim L(Nums.Length - 1) As Integer
        Dim R(Nums.Length - 1) As Integer
        Dim I As Integer
        Dim Result As Integer = 0

 

        If Nums.Length < 3 Then Return 0

 

        L(0) = 0
        R(Nums.Length - 1) = 0

        For I = 1 To Nums.Length - 2
            L(I) = Math.Max(L(I - 1), Nums(I - 1))
            R(Nums.Length - 1 - I) = Math.Max(R(Nums.Length - I), Nums(Nums.Length - I))
        Next

 

        For I = 1 To Nums.Length - 2
            If L(I) > Nums(I) AndAlso R(I) > Nums(I) Then
                Result += Math.Min(L(I), R(I)) - Nums(I)
            End If
        Next

        Return Result
    End Function
End Class

 

从代码看,该算法的时间效率是O(N)的,是线性时间的。在文章 Twitter算法面试题详解(Java实现) 的评论中也有一个线性时间的算法(效率相当,可能还优于本算法),不过理解上不如这个简单明了。

时间: 2024-11-08 05:58:32

算法实践——Twitter算法面试题(积水问题)的线性时间解法的相关文章

Twitter算法面试题详解(Java实现)

最近在网上看到一道Twitter的算法面试题,网上已经有人给出了答案,不过可能有些人没太看明白(我也未验证是否正确),现在给出一个比较好理解的答案.先看一下题目. 图1 先看看这个图.可以将方块看做砖.题干很简单,问最多能放多少水.例如,图2就是图1可放的最多水(蓝色部分),如果将一块砖看做1的话,图2就是能放10个单位的水. 图2 再看个例子 图3 图3可以放17个单位的水. 上面每一个图的砖墙用int数组表示,每一个数组元素表示每一列砖墙的砖数(高度),例如,图3用数组表示就是int[] w

数据结构与算法面试题80道

1.把二元查找树转变成排序的双向链表  题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表. 要求不能创建任何新的结点,只调整指针的指向.    10  / \  6 14  / \ / \ 4 8 12 16  转换成双向链表 4=6=8=10=12=14=16.    首先我们定义的二元查找树 节点的数据结构如下:  struct BSTreeNode {  int m_nValue; // value of node  BSTreeNode *m_pLeft; // lef

算法面试题

1.把二元查找树转变成排序的双向链表 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表. 要求不能创建任何新的结点,只调整指针的指向. 10 / \ 6 14 / \ / \ 4 8 12 16 转换成双向链表 4=6=8=10=12=14=16. 首先我们定义的二元查找树 节点的数据结构如下: struct BSTreeNode { int m_nValue; // value of node BSTreeNode *m_pLeft; // left child of nod

【算法】6 比较排序之外学习新的线性时间排序

回顾比较排序 相信阅读过前面5篇博文的童鞋们已经发现了"在排序的最终结果中,各元素的次序依赖于它们之间的比较".于是乎,这类排序算法被统称为"比较排序". 比较排序是通过一个单一且抽象的比较运算(比如"小于等于")读取列表元素,而这个比较运算则决定了每两个元素中哪一个应该先出现在最终的排序列表中. 声明:下面通过在维基百科中找到的非常完美的图示来介绍一系列比较排序. 插入排序 在该系列的[算法]1中我们便介绍了这个基本的算法,它的比较过程如下:

一道算法面试题

问题描述 有4个彩色的立方体.立方体的6个面,每面都涂上了1种颜色.一共有4种颜色,蓝色(B),红色(R),绿色(G)和黄色(Y).立方体的6个面称为前(front).后(back).左(left).右(right).上(top).下(bottom).这4个立方体的颜色排列为:编号frontbackleftrighttopbottom1RBGYBY2RGGYBB3YBRGYR4YGBRRR请将这4个立方体重叠摆放成为一个立柱,这个立柱有4个侧面,要求每个侧面都有4种颜色.用你最拿手的语言编程实现

大企业的算法面试题,等你来挑战。

问题描述 木头排列的问题:一堆长短不一的木头需要装在纸盒子里面,每一层由若干个木头组成,且木头拼接的总长度不能超过盒子的长度1200mm.使整体形成一个L型的形状.写一个算法实现功能.看你们的算法能力了,这道题是一家大型企业的面试题.具体哪一家稍后会公布,看看你们的能力了. 解决方案 解决方案二:1200mm是不是多余了?解决方案三:好难啊.好难啊.解决方案四:使整体形成L是什么意思?解决方案五:最大层数有限制吧,如果不限制的话,直接排序,然后一层只放一根木头,大的在下,小的在上..解决方案六:

某研究院的二叉树深度优先遍历变种的算法面试题以及答案

  去了某研究院面试,被面了一道算法题,觉得有点意思,所以写下来供后人参考. 题目是这样子的: 给定二叉树,二叉树的每个节点都是一个整数值,求从叶子节点到根节点的和为某数的所有路径 例如下图中,要求叶子节点到根节点的值和为14的路径为: 3,6,53,7,4 这道题考的是二叉树深度优先遍历的增强版,其实现代码如下: package cn.outofmemory; import java.util.Stack; public class TreeSum { public static void m

分享阿里巴巴综合算法面试题详解

这道题的大意是:有一个淘宝商户,在某城市有n个仓库,每个仓库的储货量不同,现在要通过货物运输,将每次仓库的储货量变成一致的,n个仓库之间的运输线路围城一个圈,即1->2->3->4->-->n->1->-,货物只能通过连接的仓库运输,设计最小的运送成本(运货量*路程)达到淘宝商户的要求,并写出代码. 解题思路: 假设n个仓库的初始储货量分别为warehouse[1],warehouse[2],-,warehouse[n] 计算平均储货量  average = (w

微软的22道数据结构算法面试题

1.反转一个链表.循环算法. 1 List reverse(List l) { 2 if(!l) return l; 3 list cur = l.next; 4 list pre = l; 5 list tmp; 6 pre.next = null; 7 while (cur) { 8 tmp=cur; 9 cur=cur.next; 10 tmp.next=pre 11 pre=tmp; 12 } 13 return tmp; 14 } 2.反转一个链表.递归算法. 1 List resve