【华为OD机试】天然蓄水池
天然蓄水池
题目描述
公元2919年,人类终于发现了一颗宜居星球——X星。现想在X星一片连绵起伏的山脉间建一个天然蓄水库,如何选取水库边界,使蓄水量最大?
要求:
山脉用正整数数组s表示,每个元素代表山脉的高度。
选取山脉上两个点作为蓄水库的边界,则边界内的区域可以蓄水,蓄水量需排除山脉占用的空间。
蓄水量的高度为两边界的最小值。
如果出现多个满足条件的边界,应选取距离最近的一组边界。
输出边界下标(从0开始)和最大蓄水量;如果无法蓄水,则返回0,此时不返回边界。
例如,当山脉为s = [3, 1, 2]时,则选取s[0]和s[2]作为水库边界,则蓄水量为1,此时输出:0 2:1 当山脉`s = [3, 2, 1]时,不存在合理的边界,此时输出:0。
输入描述
一行正整数,用空格隔开,例如输入 1 2 3 表示 s = [1, 2, 3]
输出描述
当存在合理的水库边界时,输出左边界、空格、右边界、英文冒号、蓄水量;例如 0 2:1 当不存在合理的水库边界时,输出 0;例如 0
补充说明
数组s满足: 1 <= length(s) <= 10000 0 <= s[i] <= 10000
示例
示例1
输入 1 9 6 2 5 4 9 3 7 输出 1 6:19 说明 经过分析,选取s[1]和s[6]时,水库蓄水量为19(3 + 7 + 4 + 5)
示例2
输入 1 8 6 2 5 4 8 3 7 输出 1 6:15 说明 经过分析,选取s[1]和s[8]时,水库蓄水量为15;同样选取s[1]和s[6]时,水库蓄水量也为15。由于后者下标距离小(为5),故应选取后者。
示例3
输入 1 2 3 输出 0 说明 不存在合理的水库边界。
解题思路
示例2 图示可知总容量允许分割为多段,总容量为多段汇总,与不允许分段使用双指针不同,需要考虑分段后容量超出不分段场景;
代码示例
public String maxArea(int[] s) { // 索引、最大面积 int l = 0, r = 0, max = 0; for(int m = 0, n = s.length - 1; m < n; m++) { // 升序时跳过 if(s[m] <= s[m + 1]) { continue; } // 右指针 for (int i = m + 2; i <= n; i++) { // 降序时跳过 if(s[i - 1] >= s[i]) { continue; } // 高度 int h = Math.min(s[m], s[i]); int total = Arrays.stream(s, m + 1, i) .filter(num -> num < h) .map(num -> h - num) .reduce(0, (a, b) -> a + b); // 超出已有最大面积时赋值 if(total > max) { l = m; r = i; max = total; } } } return max > 0 ? l + " " + r + ":" + max : "0"; }