Python 给定建筑物高度的积水求解算法
我正在练习算法,我在这个问题上已经坚持了几天了。当我测试我的解决方案时,我仍然不正确。以下是问题陈述: 纽约的华尔街以其惊人的摩天大楼而闻名。 但是雨季即将来临,而且 今年将有巨大的建筑物倒塌。自从 每一栋建筑都被贴在其左右两侧的建筑上 (除了第一个和最后一个),水可能从管道中泄漏 仅当建筑物的高度高于 建筑的左侧或右侧(边缘的高度 华尔街指数为0)。所有的建筑物都有1米宽。你 给出了华尔街建筑物的高度(以米为单位) 从左到右,您的任务是打印到标准输出 (stdout)在水面上的总水量(以立方米为单位) 华尔街的建筑物 输入示例:Python 给定建筑物高度的积水求解算法,python,algorithm,Python,Algorithm,我正在练习算法,我在这个问题上已经坚持了几天了。当我测试我的解决方案时,我仍然不正确。以下是问题陈述: 纽约的华尔街以其惊人的摩天大楼而闻名。 但是雨季即将来临,而且 今年将有巨大的建筑物倒塌。自从 每一栋建筑都被贴在其左右两侧的建筑上 (除了第一个和最后一个),水可能从管道中泄漏 仅当建筑物的高度高于 建筑的左侧或右侧(边缘的高度 华尔街指数为0)。所有的建筑物都有1米宽。你 给出了华尔街建筑物的高度(以米为单位) 从左到右,您的任务是打印到标准输出 (stdout)在水面上的总水量(以立方米
heights: [9 8 7 8 9 5 6]
5
示例输出:
heights: [9 8 7 8 9 5 6]
5
说明:
在本例中,第一栋和第五栋建筑之间有4立方米的水(第二栋建筑有1立方米,第三栋建筑有2立方米,第四栋建筑有1立方米),第五栋和第七栋建筑之间有1立方米的水(第六栋建筑有1立方米)
我解决这个问题的方法是找到全局最大值,并利用这些最大值的差异来计算水的积累。我用局部水变量解释了最后可能错过的水。有人能帮我找到算法或代码中的错误吗
注意:我正在寻找一种只通过每个元素一次的解决方案 以下是我有错误的输入:
heights: [8,8,4,5]
这个输入应该产生1
,而不是我的答案0
这是我的密码:
def skyscrapers(heights):
heights.insert(0,0)
heights.append(0)
local_max = 0
global_max = 0
total_water = 0
local_water = 0
end_water = []
# end_water records water heights to be used for finding
# water between the final global maximum and
# subsequent local maximums. These potential values are
# stored in local_water.
for i in range(1, len(heights)-1):
end_water.append(heights[i])
# check for local max
if heights[i-1] < heights[i] and heights[i] > heights[i+1]:
# record potential collected water for after final
# gloabl max
for s in end_water:
local_water += (heights[i] - s) * (heights[i] - s > 0)
local_max=i
# new global max
if heights[local_max] > heights[global_max]:
for s in heights[global_max:local_max]:
if heights[global_max] - s > 0:
total_water += heights[global_max] - s
global_max = local_max
local_water = 0
end_water = []
total_water += local_water
print total_water
def摩天大楼(高度):
高度。插入(0,0)
高度。追加(0)
局部_max=0
全局_max=0
总水=0
本地水=0
结束水=[]
#end_water记录用于查找的水位高度
#最终全球最大值和最大值之间的水
#随后的局部最大值。这些潜在价值是
#储存在当地的水里。
对于范围(1,长度(高度)-1)内的i:
结束水。附加(高度[i])
#检查本地最大值
如果高度[i-1]<高度[i]和高度[i]>高度[i+1]:
#记录最终试验后收集的潜在水
#gloabl最大值
对于末端水中的s:
局部水+=(高度[i]-s)*(高度[i]-s>0)
局部_max=i
#新全局最大值
如果高度[本地最大值]>高度[全局最大值]:
对于s高度[全局最大值:局部最大值]:
如果高度[global_max]-s>0:
总水+=高度[全局最大值]-s
全局最大值=局部最大值
本地水=0
结束水=[]
总水+=当地水
打印总水量
类解决方案:
#@param A,整数列表
#@返回一个整数
def存水弯(自身,A):
uTrapper=[]
i=0
leftIndex=0
rightIndex=0
#只剩下两个人没能存水
而(i)<(len(A)-2)):
leftIndex=self.findLeftBank((A[i:])+i
rightIndex=self.findRightBank((A[leftIndex+1:]),A[leftIndex])+leftIndex+1
追加((A[leftIndex:rightIndex+1]))
i=右索引
返回自我获取雨水(uTrapper)
def findLeftBank(自身,列表):
对于范围内的i(len(列表)):
curr=列表[i]
currenxt=list[i+1]如果i+1当前下一步):
返回i
返回len(列表)-1
def findRightBank(自身、列表、左高):
biggestLoc=len(列表)
最大值=0
对于范围内的i(len(列表)):
如果(列表[i]>=leftHight):
返回i
如果(列表[i]>最大值):
biggestLoc=i
最大=列表[i]
返回biggestLoc
def GetRains(自我,列表):
全部=0
对于范围内的i(len(列表)):
列表=列表[i]
高度=最小值(列表[0],列表[len(列表)-1])
对于范围(1,长度(列表)-1)内的i:
如果(列出[i]>高度):
持续
全部=全部+(高度-列表[i])
全部归还
s=解决方案()
打印s.trap([9,6,8,8,5,6,3])
上面可以吗
height
_ _
9 | |_ _| | _ _
8 | |_| | | |
7 | | _ | |
6 | |_| | | | _
5 | | | |_| |
4 | | | | _ _
3 | | | | | | _ | |
2 | | | | | |_| |_| |
1 |0 1 2 3 4 5 6| |0 1 2 3| |0 1 2 3 4| pos
这是一个基于for问题的单遍(!)(O(n)-时间)O(n)-空间算法:
我已经用蛮力O(n*m)算法对其进行了测试:
from itertools import product
def test(max_buildings=6, max_floors=6):
for nbuildings, nfloors in product(range(max_buildings), range(max_floors)):
for heights in product(range(nfloors), repeat=nbuildings):
assert max_water_heldover(heights) == max_water_heldover_bruteforce(heights), heights
其中max\u water\u heldover\u bruteforce()
是:
import sys
from colorama import Back, Fore, Style, init # $ pip install colorama
init(strip=not sys.stderr.isatty())
def max_water_heldover_bruteforce(heights):
if not heights: return 0
BUILDING, AIR, WATER = ['B', ' ',
Back.BLUE + Fore.WHITE + 'W' + Fore.RESET + Back.RESET + Style.RESET_ALL]
matrix = [[WATER] * len(heights) for _ in range(max(heights))]
for current_floor, skyscrapers in enumerate(matrix, start=1):
outside = True
for building_number, building_height in enumerate(heights):
if current_floor <= building_height:
outside = False
skyscrapers[building_number] = BUILDING
elif outside:
skyscrapers[building_number] = AIR
for i, building_height in enumerate(reversed(heights), 1):
if current_floor > building_height:
skyscrapers[-i] = AIR
else:
break
if '--draw-skyscrapers' in sys.argv:
print('\n'.join(map(''.join, matrix[::-1])), file=sys.stderr)
print('-'*60, file=sys.stderr)
return sum(1 for row in matrix for cell in row if cell == WATER)
导入系统
从colorama导入后、前、样式、初始化#$pip安装colorama
init(strip=not sys.stderr.isatty())
def max_water_heldover_bruteforce(高度):
如果不是高度:返回0
建筑、空气、水=['B','',
Back.BLUE+Fore.WHITE+W'+Fore.RESET+Back.RESET+Style.RESET\u ALL]
矩阵=[[水]*范围内的长度(高度)(最大高度))]
对于当前楼层,枚举中的摩天大楼(矩阵,起点=1):
外部=真
对于建筑物编号,枚举中的建筑物高度(高度):
如果当前楼层建筑高度:
摩天大楼[-i]=空气
其他:
打破
如果sys.argv中的“--绘制摩天大楼”:
打印('\n'.join(映射('.join,矩阵[::-1])),文件=sys.stderr)
打印('-'*60,文件=sys.stderr)
返回和(如果单元格==水,则矩阵行中的单元格为1)
结果是相同的。这里有一个单程解决方案,它改进了刘志东和J.s.Sebastian的解决方案,只使用O(1)空间: 双通道解决方案基于以下逻辑:
import sys
from colorama import Back, Fore, Style, init # $ pip install colorama
init(strip=not sys.stderr.isatty())
def max_water_heldover_bruteforce(heights):
if not heights: return 0
BUILDING, AIR, WATER = ['B', ' ',
Back.BLUE + Fore.WHITE + 'W' + Fore.RESET + Back.RESET + Style.RESET_ALL]
matrix = [[WATER] * len(heights) for _ in range(max(heights))]
for current_floor, skyscrapers in enumerate(matrix, start=1):
outside = True
for building_number, building_height in enumerate(heights):
if current_floor <= building_height:
outside = False
skyscrapers[building_number] = BUILDING
elif outside:
skyscrapers[building_number] = AIR
for i, building_height in enumerate(reversed(heights), 1):
if current_floor > building_height:
skyscrapers[-i] = AIR
else:
break
if '--draw-skyscrapers' in sys.argv:
print('\n'.join(map(''.join, matrix[::-1])), file=sys.stderr)
print('-'*60, file=sys.stderr)
return sum(1 for row in matrix for cell in row if cell == WATER)
def fillcount(elevations):
start = 0
end = len(elevations) - 1
count = 0
leftmax = 0
rightmax = 0
while start < end:
while start < end and elevations[start] <= elevations[start + 1]:
start += 1
else:
leftmax = elevations[start]
while end > start and elevations[end] <= elevations[end - 1]:
end -= 1
else:
rightmax = elevations[end]
if leftmax < rightmax:
start += 1
while start < end and elevations[start] <= leftmax:
count += leftmax - elevations[start]
start += 1
else:
end -= 1
while end > start and elevations[end] <= rightmax:
count += rightmax - elevations[end]
end -= 1
return count
def fillcount_twopass(elevations):
global_max = max(range(len(elevations)), key=lambda x: elevations[x])
count = 0
local_max = 0
for i in xrange(0, global_max):
if elevations[i] > local_max:
local_max = elevations[i]
else:
count += local_max - elevations[i]
local_max = 0
for i in xrange(len(elevations) - 1, global_max, -1):
if elevations[i] > local_max:
local_max = elevations[i]
else:
count += local_max - elevations[i]
return count
>>> rands = [random.randrange(0, 1000000) for i in xrange(10000000)]
>>> %timeit fillcount(rands)
1 loops, best of 3: 3.3 s per loop
from scipy.signal import argrelextrema
import numpy as np
def local_max_scipy(a):
minima = argrelextrema(a, np.greater_equal)[0]
return minima
def water_cumulative(buildings):
local_maxima=local_max_scipy(buildings)
water = 0
# 2 or more maxima => there is water
if len(local_maxima)>1:
# in the middle of every couple of local maxima
for i in range((len(local_maxima)-1)):
reference = 0
#pick the shorter building between the two maxima as reference
if buildings[local_maxima[i]] >= buildings[local_maxima[i+1]]:
reference = buildings[local_maxima[i+1]]
else:
reference = buildings[local_maxima[i]]
#cumulate the water
for j in range(local_maxima[i+1]-local_maxima[i]):
# just exit when building higher than the reference is found
if buildings[local_maxima[i]+1+j] < reference:
water = water + reference - buildings[local_maxima[i]+1+j]
else:
break
return water
buildings01 = np.array([3, 2, 1, 4, 5])
buildings02 = np.array([1, 2, 3, 4, 5])
buildings03 = np.array([9, 8, 7, 8, 9, 5, 6])
buildings04 = np.array([8, 8, 4, 5])
>>>water_cumulative(buildings01)
3
>>>water_cumulative(buildings02)
0
>>>water_cumulative(buildings03)
5
>>>water_cumulative(buildings04)
1
SectorCalculation<- function(vector){
## It outputs in a list the different side roofs
counter<-1
vectorList<- list()
## While vector is larger than 2
## Choose the max value in the string appart from the left value
### If it finds it, then that is the sector, eliminate it and start again
### the procedure with the part of the vector left
### Else , go to next index
while(length(vector)>2){
vecleft<-StartChoice(vector)
if(all.equal(vecleft,rep(0,length(vecleft)))!=TRUE){
global_max<- max(vecleft[2:length(vecleft)])
left<- vecleft[1]
for(i in 2:length(vecleft)){
if(i > length(vecleft)){
return(vectorList)}
else{
if(vecleft[i]==global_max){
vectorList[[counter]]<-vecleft[1:i]
vector<- vecleft[i:length(vecleft)]
counter<- counter+1
break
}
}
}
}else{return(0)}
}
return(vectorList)
}
StartChoice<- function(vecHeights){
## It gives back the vector discarding zero values at the beginning
leftval<-integer(0)
ChooseStart <- TRUE
for(i in 1:length(vecHeights)){
if(length(leftval)==0){
leftval[1]<- vecHeights[i]
}
else if(i == length(vecHeights)){return(0)}
else {
if(vecHeights[i] >= leftval){
leftval[1]<- vecHeights[i]
}
else{
ChooseStart <- FALSE
vectorleft<-vecHeights[(i-1):length(vecHeights)]
break
}
}
}
return(vectorleft)
}
AreaCalculation<-function(HeightsPassed){
## Select the second highest value between left and right and
## compute the value in the roof
highest<- min(HeightsPassed[1], HeightsPassed[length(HeightsPassed)])
Res<-(highest-HeightsPassed)[(highest-HeightsPassed)>0]
# Selecting only those values higher than 0
TotWater<-sum(Res)
return(TotWater)
}
main<-function(Heights){
## if value containing values <= 0, out
if(all.equal((Heights <= 0), rep(FALSE, length(Heights)))!=TRUE){
stop("Either values equal or lower than 0 or non-numeric values supplied")
}
## Get in a list all the sectors to be calculated
MyHeightslist<-SectorCalculation(Heights)
## If list different than a list 0 with a 0, then
## just calculate by parts the water in the roofs; then sum it
if(all.equal(MyHeightslist[[1]],rep(0,length(MyHeightslist[[1]])))!=TRUE)
{
byParts<-sapply(MyHeightslist, AreaCalculation)
TotalWater<-sum(byParts)
}
else{return(0)}
return(TotalWater)
}
main(c(1,2,3))
[1] 0
main(c(9,8,7,8,9,5,6))
[1] 5
main(c(8,9,9,8,7,8,9,5,6))
[1] 5
main(c(8, 8, 4, 5))
[1] 1
main(c(3,1,3,1,1,3))
[1] 6
main(c(1,2,3,4))
[1] 0
main(c(3,2,1))
[1] 0