我需要在大学里完成一个小练习,但是我已经卡了一段时间了。这个练习是关于计算2D数组的水容量,用户需要输入2D数组的宽度(w)和高度(h),然后输入数组中每个元素的值,这些值代表该位置的高度。下面是一个非常简单的例子:
10 10 10
10 2 10
10 10 10
输出将会是8,因为那是可以装入容器的最大水量。另一个例子是:
6 4
1 5 1 5 4 3
5 1 5 1 2 4
1 5 1 4 1 5
3 1 3 6 4 1
输出将为14。
还需要提及的是:数组的宽度和高度不能大于1000,元素的高度不能大于10 ^ 5。
现在我基本上有了解决方案,但对于更大的输入速度不够快。我的做法是:将高度添加到TreeSet中,然后每次轮询最后一个(最高的)高度,然后遍历数组(不考虑边缘),使用DFS并检查每个位置是否可以留下水。如果水不流出数组,则计算处于水下的位置,如果超出数组范围,则再次轮询并执行相同操作。
我还尝试查看数组中的峰值,通过垂直和水平查找。对于上面的示例,您会得到以下结果:
0 5 0 5 4 0
5 0 5 0 0 4
0 5 0 4 0 5
3 1 3 6 4 0
我用这个方法给峰顶着色,比如说黑色,然后对于所有白色颜色,再次使用DFS找到最小的峰值,然后用这个最小值来计算水容量。但是这种方法行不通,因为举个例子:
7 7 7 7 7
7 4 4 4 7
7 2 3 1 7
7 4 4 4 7
7 7 7 7 7
现在水位到处都是7,但3是一个山峰,所以这种方法行不通。
但由于我的解决方案不够快,我正在寻找更高效的解决方案。以下代码是其中神奇部分:
while (p.size() != 0 || numberOfNodesVisited!= (w-2)*(h-2)) {
max = p.pollLast();
for (int i=1; i < h-1; i++) {
for (int j=1; j < w-1; j++) {
if (color[i][j] == 0) {
DFSVisit(profile, i, j);
if (!waterIsOut) {
sum+= solveSubProblem(heights, max);
numberOfNodesVisited += heights.size();
for(int x = 0; x < color.length; x++) {
color2[x] = color[x].clone();
}
} else {
for(int x = 0; x < color2.length; x++) {
color[x] = color2[x].clone();
}
waterIsOut = false;
}
heights.clear();
}
}
}
}
注意,我每次都重置路径和颜色,我认为这是需要改进的部分。
对于我的深度优先搜索(DFS)来说,我有三种颜色:2(黑色)表示已访问,1(灰色)表示是一条边,0(白色)表示未访问且不是一条边。
public void DFSVisit(int[][] profile, int i, int j) {
color[i][j] = 2; // black
heights.add(profile[i][j]);
if (!waterIsOut && heights.size() < 500) {
if (color[i+1][j] == 0 && max > profile[i+1][j]) { // up
DFSVisit(profile, i+1, j);
} else if (color[i+1][j] == 1 && max > profile[i+1][j]) {
waterIsOut = true;
}
if (color[i-1][j] == 0 && max > profile[i-1][j]) { // down
DFSVisit(profile, i-1, j);
} else if (color[i-1][j] == 1 && max > profile[i-1][j]) {
waterIsOut = true;
}
if (color[i][j+1] == 0 && max > profile[i][j+1]) { // right
DFSVisit(profile, i, j+1);
} else if (color[i][j+1] == 1 && max > profile[i][j+1]) {
waterIsOut = true;
}
if (color[i][j-1] == 0 && max > profile[i][j-1]) { //left
DFSVisit(profile, i, j-1);
} else if (color[i][j-1] == 1 && max > profile[i][j-1]) {
waterIsOut = true;
}
}
}
更新 @dufresnb提到talentbuddy.co在https://www.talentbuddy.co/challenge/526efd7f4af0110af3836603上提供了相同的练习。然而,我测试了许多解决方案,其中一些实际上通过了我的前四个测试用例,但大多数在简单的测试用例上已经失败。Talent Buddy在制作测试用例方面做得很差:实际上他们只有两个测试用例。如果您想查看他们的解决方案,只需注册并输入此代码(语言为C)即可通过其测试用例。
#include <stdio.h>
void rain(int m, int *heights, int heights_length) {
//What tests do we have here?
if (m==6)
printf("5");
else if (m==3)
printf("4");
//Looks like we need some more tests.
}
更新 @tobias_k的解决方案是可行的,但像我的解决方案一样,它不足以通过更大的输入测试用例,有没有更有效的实现方法?
任何想法和帮助将不胜感激。
O(K*N^2)
,可能通过一些优化为O(N^2)
。不确定这是否比你的更好或更差。 - tobias_k