一道算法面试题-接雨水
朋友去XX书面试IOS开发,面试有一道算法题做不出来,事后发给我看了一下,然而,我不会OC,就用C#写了一下,题目如下:
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]输出:6解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 示例 2:
输入:height = [4,2,0,3,2,5]输出:9
解题思路:途中蓝色部分是储水位置,特点:蓝色区块左右两侧必须都有比自己高的柱子,也就是[1,0,1]、[3、0、0、2]这种结构。
比较简单的算法是:
1.我们可以从最下面一行逐行进行计算,当数值为0,且两边能找到为0节点的时候,存在储水空间
2.每一行计算完成之后,把集合的数值全部-1,再次重复第一步
3.重复上面两步,总共要计算集合中最大值的行数。
具体代码如下:
using System; using System.Collections.Generic; using System.Linq; namespace ConsoleApp1 { class Program { private static List<int> NumList { get; set; } static void Main(string[] args) { InitNumList();//初始化集合 var total = 0;//总共储水量 var max = NumList.Max();//最高柱子 var iCount = NumList.Count;//集合数量 for (int l = 0; l < max; l++)//进行分行计算 { var line = 0;//每一行的储水量 var start = -1;//定义每一个储水空间的起始节点 for (int i = 0; i < iCount; i++)//循环当前行 { var num = NumList[i]; if (num > 0 && start == -1)//取开始节点 { start = i; } else if (num > 0 && start > -1)//取结束节点 { var water = i - start - 1;//两节点间的储水量 if (water > 0)//当water=0的时候,开始节点和结束节点刚好相同,这时候没办法储水 { total += i - start - 1;//累加总储水量 line += i - start - 1;//累加当前行储水量 } start = i;//重置开始节点 } } Console.WriteLine($"line:{line}"); for (int i = 0; i < iCount; i++)//循环将集合里的非0数字全部-1 { if (NumList[i] > 0) { NumList[i]--; } } } Console.WriteLine($"total:{total}"); } /// <summary> /// 初始化集合 /// </summary> private static void InitNumList() { //NumList = new List<int>() { 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 }; NumList = new List<int>() { 4, 2, 0, 3, 2, 5 }; } } }