问题描述:在下图里我们有不同高度的挡板。这个图片由一个整数数组所代表,数组中每个数是墙的高度。下图可以表示为数组(2、5、1、2、3、4、7、2)。假如开始下雨了,那么挡板之间的水坑能够装多少水(水足够多)呢?
下图是装满水的情况,一个蓝色格子代表一个单位的水。下图中一共装了10个单位的水。
上周参加某大型互联网公司面试,结果死在这道算法上。
我给出的算法: 积水面积 = 总面积 - 砖面积 - 无砖无水面积
思想就是化复杂为简单,直接求积水面积不太好求,那就求比它更简单的。
比如总面积,砖的面积都非常简单。
无砖无水面积也不难求,从两侧最小的开始,遇到比自己大的,开始递归。
// 面试时的算法(积水面积=总面积-砖面积-无砖无水面积) public static int fill1(int[] nums) { if (nums.length < 3) { return 0; } int max = 0; int sum = 0; for (int i = 0; i <= nums.length - 1; i++) { max = Math.max(max, nums[i]); sum += nums[i]; } // 积水面积=总面积-砖面积-无砖无水面积 return max * nums.length - sum - fill1(nums, max, 0, nums.length - 1); } // 求无砖无水面积(从两侧最小值开始计算,遇上更大的开始递归) private static int fill1(int[] nums, int max, int start, int end) { int sum = 0; if (nums[start] <= nums[end]) { int v = nums[start]; sum += max - v; for (int i = start + 1; i <= end; i++) { if (nums[i] > v) { sum += fill1(nums, max, i, end); break; } else { sum += max - v; } } } else { int v = nums[end]; sum += max - v; for (int i = end - 1; i >= start; i--) { if (nums[i] > v) { sum += fill1(nums, max, start, i); break; } else { sum += max - v; } } } return sum; }
无砖无水面积的算法,稍微改动下就可以算砖和水的面积。
于是我改良了下算法:积水面积 = 砖和水面积 - 砖面积
// 改良后的算法(积水面积=砖和水面积-砖面积) public static int fill2(int[] nums) { if (nums.length < 3) { return 0; } int sum = 0; for (int i = 0; i <= nums.length - 1; i++) { sum += nums[i]; } // 积水面积=砖和水面积-砖面积 return fill2(nums, 0, nums.length - 1) - sum; } // 求砖和水的面积(从两侧最小值开始计算,遇上更大的开始递归) private static int fill2(int[] nums, int start, int end) { int sum = 0; if (nums[start] <= nums[end]) { int v = nums[start]; sum += v; for (int i = start + 1; i <= end; i++) { if (nums[i] > v) { sum += fill2(nums, i, end); break; } else { sum += v; } } } else { int v = nums[end]; sum += v; for (int i = end - 1; i >= start; i--) { if (nums[i] > v) { sum += fill2(nums, start, i); break; } else { sum += v; } } } return sum; }
网上找到一个算法:求砖左右的挡板, 每堆砖积水量 = 最低挡板高 - 砖高
由于多出两个数组存储和遍历左右挡板,因此性能并不可观。算法出处
// 网上找到的算法(仅供性能对比) public static int fill0(int[] nums) { if (nums.length < 3) { return 0; } int[] l = new int[nums.length]; int[] r = new int[nums.length]; int result = 0; l[0] = 0; r[nums.length - 1] = 0; for (int i = 1; i <= nums.length - 2; i++) { 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]); } for (int i = 1; i <= nums.length - 2; i++) { if (l[i] > nums[i] && r[i] > nums[i]) { result += Math.min(l[i], r[i]) - nums[i]; } } return result; }
现在来对比下性能。
public static void main(String[] args) { int[] nums = new int[] { 2, 5, 1, 2, 3, 4, 7, 2 }; StringBuilder sb = new StringBuilder(); if (nums.length > 0) { sb.append(nums[0]); } for (int i = 1; i < nums.length; i++) { sb.append("," + nums[i]); } System.out.println(MessageFormat.format("输入参数: {0}", sb)); System.out.println(MessageFormat.format("网上算法结果: {0}", FillWater.fill0(nums))); System.out.println(MessageFormat.format("面试算法结果: {0}", FillWater.fill1(nums))); System.out.println(MessageFormat.format("改良算法结果: {0}", FillWater.fill2(nums))); int n = 100000000; System.out.println(MessageFormat.format("执行次数: {0} 次", n)); long time = System.currentTimeMillis(); for (int i = 0; i < n; i++) { FillWater.fill0(nums); } System.out.println(MessageFormat.format("网上算法耗时: {0} ms", System.currentTimeMillis() - time)); time = System.currentTimeMillis(); for (int i = 0; i < n; i++) { FillWater.fill1(nums); } System.out.println(MessageFormat.format("面试算法耗时: {0} ms", System.currentTimeMillis() - time)); time = System.currentTimeMillis(); for (int i = 0; i < n; i++) { FillWater.fill2(nums); } System.out.println(MessageFormat.format("改良算法耗时: {0} ms", System.currentTimeMillis() - time)); }
结果如下:
输入参数: 2,5,1,2,3,4,7,2 网上算法结果: 10 面试算法结果: 10 改良算法结果: 10 执行次数: 100,000,000 次 网上算法耗时: 5,445 ms 面试算法耗时: 2,382 ms 改良算法耗时: 1,936 ms
面试时给出的算法: 积水面积 = 总面积 - 砖面积 - 无砖无水面积
虽然不是最优算法,但也是一种思维,不能算完全错误吧
相关推荐
积水问题是一种经典的计算机科学问题,通常出现在算法面试和编程竞赛中。它涉及到寻找二维或一维数组中的“洼地”,并计算在虚拟降雨后能够蓄积的水量。这里我们将详细探讨一维和二维积水问题的解决方案。 对于一维...
积水目标检测是这两个领域的交叉应用,通过人工智能的算法和计算机视觉的理论,我们可以训练模型自动识别和理解图像中的积水,进而辅助决策或预警系统。 坑洼积水数据集的文件名称虽然没有提供具体信息,但可以推测...
积水检测数据集是一个重要的资源,尤其对于那些在计算机视觉领域工作,...通过这个数据集,研究人员和开发者可以训练和评估自己的目标检测算法,尤其是在积水场景的应用,为智能交通、城市规划等领域带来创新解决方案。
### 计算机方面面试题库(算法) #### 1. 中序迭代器 - **难度**: 2 - **问题描述**: 设计一个迭代器,实现对一棵二叉树进行中序遍历的功能。 - **问题提供者**: free - **验证者**: DaLong - **时间复杂度**: O(n)...
alexnet模型_基于图像分类算法对是否积水识别-不含数据集图片-含逐行注释和说明文档 本代码是基于python pytorch环境安装的。 下载本代码后,有个环境安装的requirement.txt文本 如果有环境安装不会的,可自行网上...
然而,由于煤矿环境潮湿和粉尘较多,电控箱内部积水问题一直是一个技术难题。积水不仅会影响电控箱内电子元件的正常工作,还可能引发短路甚至爆炸,给矿井安全带来极大隐患。因此,研究并解决电控箱内部积水问题显得...
本研究文档关注于开发一种基于迁移学习算法的人工智能模型,用于脑积水的影像诊断,以及对该模型在临床上的应用和效果评估。脑积水是一种神经科常见的疾病,其特征为脑脊液循环异常导致脑室系统积水。传统的诊断方法...
当这三脏器功能失调,水液代谢就会出现问题,导致积液形成。比如,脾肾阳虚可能导致水湿内停,肺气不足则无法正常疏泄水液,从而形成积水。 中医治疗积水的方法多样,包括中药、针灸、拔罐等。其中,中药治疗积水时...
我国矿井水文地质类型非常复杂...分析了采空区积水的来源和通道,对8101工作面的采空区积水问题提出了治理的方案。通过在相邻5102巷道打钻孔的方案顺利解决了8101工作面采空区积水问题,实践效果良好,节省资金,优点显著。
【房地产土建工程施工师面试题解析】 面试房地产土建工程施工师时,面试官可能会提出一系列问题,以评估应聘者的专业技能、项目管理能力和协调沟通技巧。以下是对面试题的详细解答: **问题一:谈谈你自己的优点**...
采煤机电控箱是采煤机的核心设备,所以必须要求电控箱可靠、稳定。而在井下工作时电控箱经常出现漏水、积水的现象,导致电器件损坏,设备不能...针对电控箱漏水、积水问题提出了解决办法,为今后采煤机的设计提供了参考。
针对采空区积水问题,文中提出了预防措施,包括严格控制工作面的开采进度和斜长变化,加强工作面斜长变化的调整,提高测量精度,避免积水对开采活动的影响。此外,还应该加强两巷的推进度控制,以避免因斜长变化过大...
电控箱的性能对煤矿的安全高效开采起着关键...电控箱由于水蒸气进入造成的积水问题,经常导致变频器烧毁,给煤矿的安全生产带来较大隐患。分析了电控箱积水原因,并提出增加防爆栅栏的解决方案,具有很好的应用和推广价值。
数据集格式:Pascal VOC格式(不包含分割的txt文件,仅仅包含jpg图片和对应的...重要说明:这是检测道路上是否有积水的数据集 特别声明:本数据集不对训练的模型或者权重文件精度作任何保证,数据集只提供准确且合理标注
针对橡胶输送带凹陷处在雨天易形成局部积水无法及时检测的问题,研究并提出了一种基于机器视觉的橡胶输送带积水识别方法。首先对采集图像预处理,通过直方图均衡化提高图像对比度,然后利用图像坐标自动截取感兴趣区域,...