[面试题]可以盛放多少水呢?

来源:互联网 发布:mix拍照软件下载 编辑:程序博客网 时间:2024/04/29 05:52

题目:


如上图片是题目意思,读完这个题目我们应该有一个直观的认识:只有出现两侧高中间低u型槽的情况中间才可能装水。 问题变成了,怎么找到u型槽呢?

从这个图例来看,当我们从左往右扫描的时候,可以发现:

a, 第1,2,3块墙能形成一个u型槽,这个槽能蓄水1个单位

b, 第1,2,3,4 能蓄水3个单位,包括上一步骤(a)的水,实际上由于墙4的加入在(a)的基础上增加了2个单位的蓄水,同时可以看出墙4个加入实际上是

        和墙1在高度为2的基础上形成了一个宽度为2高度为1的u型槽,以此类推后面各个墙,我们可以依次计算出可以蓄水的总量。

基于这个思路,可以用一个栈来维护一个高度为递减的墙:

1, 当前栈为空,那么直接将改墙压入栈,同时需要记录这个入栈元素的下标(方便后面计算u型槽的宽度)

2, 栈不为空:

       a, 当前墙比栈顶的墙高度低,那么直接入栈,同样需要记录入栈元素的下标。

       b,当前墙和栈顶的墙高度相同,那么直接扔掉当前墙(这个墙的高度可以用栈顶的替代)

       c, 当前墙比栈顶墙高度高,这时候就形成了一个u型槽,那么需要计算这个u型槽所能蓄的水量

                     u型槽宽度 =  两高墙的下标差 - 1

                     u型槽高度 =  两侧高墙的高度较小者 - u型槽底部墙的高度

                     两者乘积便是蓄水量

              反复这个过程,直到当前墙的高度小于栈顶或者栈顶为空,然后入栈,记录下标。

由于整个算法过程,每个元素最多进行一个入栈和出栈操作,所以时间复杂度为O(N)进行一遍扫描就行了, 这个过程只需要维护一个最多保存所有元素的栈所以空间复杂度也是O(N)

#include<stdio.h>                                                                                            #include<string.h>#include<memory.h>int min(const int a, const int b){    return a > b ? b : a;}int main( int argc, char **argv){    int N;    int array[1024];    int idx = 0;    scanf("%d", &N );    for( idx = 0; idx < N; ++idx )    {        scanf("%d", array + idx);    }    int top = 0;    int stack[1024];    int index[1024];    int area = 0;    idx = 0;    while ( idx < N )    {        //栈里至少有两面墙,并且当前墙高度大于栈顶的墙,才能形成v型槽        //由于栈里始终维护的是一个高度递减的墙,所以当前墙可能和栈里的墙能形成多个u型槽        while ( top > 1 && array[idx] > stack[top - 1 ])         {            //计算u型槽的底部宽度            int length = idx - index[top - 2] - 1;             //计算u型槽的高度,两侧较低的墙 减掉  栈顶的墙高度,就是u型槽能蓄水的高度            int height = min(array[idx], stack[top - 2]) - stack[top - 1];             area += length * height;             //出栈,保持栈里的墙是递减的            top--;        }         //栈里只有一个元素,那么必然无法形成u型槽,所以直接弹出站        if ( top == 1 && array[idx] > stack[top - 1])        {            top --;        }        index[top] = idx;        stack[top++] = array[idx++];    }    printf("area = %d\n", area);    return 0;}