最近在类似glassdoor的网站上遇到了一个面试问题,我无法找到解决此问题的优化解决方案:
这与陷阱水问题完全不同。请仔细阅读示例。
给定一个输入数组,其中每个元素代表塔的高度,浇注的水量和索引号表示浇注水的位置。每个塔的宽度为1.浇注水后打印图形。
备注:
使用*
表示塔,w
代表1个水量。
浇注位置永远不会处于最高位置。不需要考虑分水箱。
(如果你为这种情况提供了一个解决方案的补充点,你可以假设如果在高峰位置倾倒N水,N / 2水向左移动,N / 2水向右移动。)
< / LI> 醇>峰值的定义:峰值位置的高度大于旁边的左右两个索引。)
假设柱状图附近有2个极高的墙壁
因此,如果水量超过直方图的容量,
你应该指出容量数字并继续。见例2.
假设水首先离开,参见示例1
示例1:
int[] heights = {4,2,1,2,3,2,1,0,4,2,1}
It look like:
* *
* * **
** *** **
******* ***
+++++++++++ <- there'll always be a base layer
42123210431
Assume given this heights array, water amout 3, position 2:
打印:
* *
*ww * **
**w*** **
******* ***
+++++++++++
示例2:
int[] heights = {4,2,1,2,3,2,1,0,4,2,1}, water amout 32, position 2
打印:
capacity:21
wwwwwwwwwww
*wwwwwww*ww
*www*www**w
**w***ww**w
*******w***
+++++++++++
起初我虽然它像the trapping water problem但我错了。有没有人有算法来解决这个问题?
欢迎代码中的解释或评论。
注意:
要求捕集水问题的容量,但这个问题引入了两个变量:水量和倾倒指数。此外,水有流动的偏好。所以它不像陷阱水问题。
答案 0 :(得分:1)
由于你必须生成并打印出数组,我可能会选择一种保持O(rows*columns)
复杂度的递归方法。注意每个单元格可以被访问&#34;最多两次。
在高级别:首先递减,然后向左,然后向右,然后填充当前单元格。
但是,这会遇到一个小问题:(假设这是一个问题)
*w * * *
**ww* * instead of **ww*w*
这可以通过更新算法来更正左边和右边的第一个 当前行,然后左右两个再次来填充当前行。让我们说 您可以通过使用堆栈避免重复访问单元格,但它更复杂。 <强>的伪代码:强> state = v
意味着我们来自上方,state = h1
意味着它是第一个水平传球,state = h2
意味着它是第二个水平传球。< / p>
array[][] // populated with towers, as shown in the question
visited[][] // starts with all false
// call at the position you're inserting water (at the very top)
define fill(x, y, state):
if x or y out of bounds
or array[x][y] == '*'
or waterCount == 0
return
visited = true
// we came from above
if state == v
fill(x, y+1, v) // down
fill(x-1, y, h1) // left , 1st pass
fill(x+1, y, h1) // right, 1st pass
fill(x-1, y, h2) // left , 2nd pass
fill(x+1, y, h2) // right, 2nd pass
// this is a 1st horizontal pass
if state == h1
fill(x, y+1, v) // down
fill(x-1, y, h1) // left , 1st pass
fill(x+1, y, h1) // right, 1st pass
visited = false // need to revisit cell later
return // skip filling the current cell
// this is a 2nd horizontal pass
if state == h2
fill(x-1, y, h2) // left , 2nd pass
fill(x+1, y, h2) // right, 2nd pass
// fill current cell
if waterCount > 0
array[x][y] = 'w'
waterCount--
答案 1 :(得分:1)
你有一个数组height
,每列都有地形的高度,所以我会创建一个这个数组的副本(我们称之为水w
)来表示水的高度在每一栏中。像这样你也可以摆脱不知道在转换成网格时要初始化多少行的问题,你可以完全跳过这一步。
Java代码中的算法如下所示:
public int[] getWaterHeight(int index, int drops, int[] heights) {
int[] w = Arrays.copyOf(heights);
for (; drops > 0; drops--) {
int idx = index;
// go left first
while (idx > 0 && w[idx - 1] <= w[idx])
idx--;
// go right
for (;;) {
int t = idx + 1;
while (t < w.length && w[t] == w[idx])
t++;
if (t >= w.length || w[t] >= w[idx]) {
w[idx]++;
break;
} else { // we can go down to the right side here
idx = t;
}
}
}
return w;
}
即使有很多循环,复杂性也只有O(drop * columns)。如果你期望大量的下降,那么根据最高地形点O(列)计算空的空间数是明智的,那么如果下降的数量超过空闲空间,则列高度的计算变得微不足道O(1),但是设置它们仍然需要O(列)。
答案 2 :(得分:1)
我找到了这个问题的Python解决方案。但是,我不熟悉Python所以我在这里引用代码。希望有人知道Python可以提供帮助。
代码@z026
def pour_water(terrains, location, water):
print 'location', location
print 'len terrains', len(terrains)
waters = [0] * len(terrains)
while water > 0:
left = location - 1
while left >= 0:
if terrains[left] + waters[left] > terrains[left + 1] + waters[left + 1]:
break
left -= 1
if terrains[left + 1] + waters[left + 1] < terrains[location] + waters[location]:
location_to_pour = left + 1
print 'set by left', location_to_pour
else:
right = location + 1
while right < len(terrains):
if terrains[right] + waters[right] > terrains[right - 1] + waters[right - 1]:
print 'break, right: {}, right - 1:{}'.format(right, right - 1)
break
right += 1
if terrains[right - 1] + waters[right - 1] < terrains[location] + waters[right - 1]:
location_to_pour = right - 1
print 'set by right', location_to_pour
else:
location_to_pour = location
print 'set to location', location_to_pour
waters[location_to_pour] += 1
print location_to_pour
water -= 1
max_height = max(terrains)
for height in xrange(max_height, -1, -1):
for i in xrange(len(terrains)):
if terrains + waters < height:
print ' ',
elif terrains < height <= terrains + waters:
print 'w',
else:
print '+',
print ''
答案 3 :(得分:1)
您可以从下到上遍历2D网格,为每个连续单元格的水平运行创建一个节点,然后将这些节点串在一起,形成一个链表,表示单元格的填充顺序。
在第一行之后,您有一个水平运行,体积为1:
1(1)
在第二行中,您会发现三个运行,其中一个连接到节点1:
1(1)->2(1) 3(1) 4(1)
在第三行中,您会发现三次运行,其中一次连接运行2和3;第3次运行最接近添加水的列,因此它首先出现:
3(1)->1(1)->2(1)->5(3) 6(1) 4(1)->7(1)
在第四行中,您会发现两次运行,其中一次连接运行6和7;第6步最接近添加水的柱子,因此它首先出现:
3(1)->1(1)->2(1)->5(3)->8(4) 6(1)->4(1)->7(1)->9(3)
在第五行中,您会找到连接第8和第9行的运行;它们位于添加水的色谱柱的两侧,因此左侧的运行首先出现:
3(1)->1(1)->2(1)->5(3)->8(4)->6(1)->4(1)->7(1)->9(3)->A(8)
运行A组合所有列,因此它成为最后一个节点,并被赋予无限的音量;任何多余的水滴都会被叠加:
3(1)->1(1)->2(1)->5(3)->8(4)->6(1)->4(1)->7(1)->9(3)->A(infinite)
答案 4 :(得分:1)
这是我的20分钟解决方案。每一滴都告诉客户端它将保留在哪里,因此完成了艰巨的任务。( IDE中的复制粘贴)现在只需要进行打印,但是滴点正在占据他们的位置。看看:
class Test2{
private static int[] heights = {3,4,4,4,3,2,1,0,4,2,1};
public static void main(String args[]){
int wAmount = 10;
int position = 2;
for(int i=0; i<wAmount; i++){
System.out.println(i+"#drop");
aDropLeft(position);
}
}
private static void aDropLeft(int position){
getHight(position);
int canFallTo = getFallPositionLeft(position);
if(canFallTo==-1){canFallTo = getFallPositionRight(position);}
if(canFallTo==-1){
stayThere(position);
return;
}
aDropLeft(canFallTo);
}
private static void stayThere(int position) {
System.out.print("Staying at: ");log(position);
heights[position]++;
}
//the position or -1 if it cant fall
private static int getFallPositionLeft(int position) {
int tempHeight = getHight(position);
int tempPosition = position;
//check left , if no, then check right
while(tempPosition>0){
if(tempHeight>getHight(tempPosition-1)){
return tempPosition-1;
}else tempPosition--;
}
return -1;
}
private static int getFallPositionRight(int position) {
int tempHeight = getHight(position);
int tempPosition = position;
while(tempPosition<heights.length-1){
if(tempHeight>getHight(tempPosition+1)){
return tempPosition+1;
}else if(tempHeight<getHight(tempPosition+1)){
return -1;
}else tempPosition++;
}
return -1;
}
private static int getHight(int position) {
return heights[position];
}
private static void log(int position) {
System.out.println("I am at position: " + position + " height: " + getHight(position));
}
}
当然,代码可以进行优化,但那是我直截了当的解决方案
答案 5 :(得分:0)
l=[0,1,0,2,1,0,1,3,2,1,2,1]
def findwater(l):
w=0
for i in range(0,len(l)-1):
if i==0:
pass
else:
num = min(max(l[:i]),max(l[i:]))-l[i]
if num>0:
w+=num
return w
答案 6 :(得分:0)
master-old