接雨水问题

Posted on 2019-01-07 16:54  云起  阅读(4)  评论(0编辑  收藏  举报  来源

问题来源于leetcode.42。

问题描述:

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

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

解题过程:

1、最开始,尝试了遍历寻找左右边界,然后累计体积的方式。

从左侧开始,依次进行遍历,判断该点左侧和右侧都有比自己当前值高的点,表示该点可以积水,然后进行单点体积计算,累加到结果量中。

public int Trap(int[] height)
        {

            int re = 0;

            for (int i = 1; i < height.Length - 1; i++)
            {
                int mid = height[i];
                int le = i, ri = i;
                int tl = mid, tr = mid;
                for (int j = i - 1; j >= 0; j--)
                {
                    if (height[j] >= tl)
                    {
                        le = j;
                        tl = height[j];
                    }
                    else
                    { };
                }

                for (int j = i + 1; j < height.Length; j++)
                {
                    if (height[j] >= tr)
                    {
                        ri = j;
                        tr = height[j];
                    }
                    else
                    { };
                }

                if (le != i && ri != i)
                {

                    int h = Math.Min(height[le], height[ri]);
                    //for(int j=le+1;j<ri;j++)
                    {
                        re += (h - height[i] > 0) ? h - height[i] : 0;
                    }
                }
            }
            return re;
        }

但是这样基于单点左右查找,算法复杂度为O(n*n),当数组比较大时,值比较和嵌套遍历,都会比较耗时,不得已进行算法简化。

2、分水岭

仔细观察储水后状态,发现其实个凸形结构,像是个梯田。从左侧开始,逐级攀爬到封顶,然后是平顶,再从平顶逐级下落。所以把过程分为左攀爬,右攀爬,平顶三个过程,分别计算累加。

public int Trap(int[] height)
        {
            int re = 0;
            if (height.Length < 3) return re;
            int max = height.Max();

            int fm = Array.IndexOf(height, max);
            int lm = Array.LastIndexOf(height, max);

            int tmp = 0;
            for (int i = 0; i < fm; i++)
            {
                if (height[i] > tmp) tmp = height[i];
                else if (height[i] < tmp)
                {
                    re += tmp - height[i];
                }
            }

            tmp = 0;
            for (int i = height.Length - 1; i > lm; i--)
            {
                if (height[i] > tmp) tmp = height[i];
                else if (height[i] < tmp)
                {
                    re += tmp - height[i];
                }
            }

            for (int i = fm; i < lm; i++)
            {
                re += max - height[i];
            }

            return re;
        }

 

Copyright © 2024 云起
Powered by .NET 9.0 on Kubernetes