水平面上有 N 座大楼,每座大楼都是矩阵的形状,可以用一个三元组表示 (start, end, height),分别代表其在x轴上的起点,终点和高度。大楼之间从远处看可能会重叠,求出 N 座大楼的外轮廓线。
外轮廓线的表示方法为若干三元组,每个三元组包含三个数字 (start, end, height),代表这段轮廓的起始位置,终止位置和高度。
注意事项: 请注意合并同样高度的相邻轮廓,不同的轮廓线在x轴上不能有重叠。
样例:
给出三座大楼:
[
[1, 3, 3],
[2, 4, 4],
[5, 6, 1]
]
外轮廓线为:
[
[1, 2, 3],
[2, 4, 4],
[5, 6, 1]
]
如图所示:
将每一栋楼切割成单位为1的单元块,然后判断去除重复单元块(坐标相同,取更高的一块),最后合并相邻并且高度一致的单元块得到结果。判重方法选择转化成字典比较直观。
def shape(pos):
# 切割成单元块
new_pos = []
for bd in pos:
if bd[1] -bd[0] > 1:
for i in range(bd[0], bd[1]):
new_pos.append([i, i+1, bd[2]])
else:
new_pos.append(bd)
print(new_pos)
# 转换成字典,坐标元组(start, end)作为key, 高度height作为value
d = {}
pp = list(map(lambda x: ((x[0], x[1]), x[2]), new_pos))
for item in pp:
k, v = item
if not d.get(k, None):
d[k] = v
else:
if v > d[k]:
d[k] = v
print(d)
# 合并高度相同的单元块
keys = list(d.keys())
keys.sort(key=lambda x: x[0]) # 按照坐标排序
pre = None
for k in keys:
if not pre:
pass
else:
if d[pre] == d[k]: # 判断上一个单元块的高度是否与当前相同,如果是则合并
d[(pre[0], k[1])] = d[k] # 合并块的新坐标(前一单元块的坐标最小值,当前单元块的坐标最大值)
d.pop(pre) # 删除已合并的单元快
d.pop(k)
k = (pre[0], k[1]) # 重置标记前一块为新合并块
pre = k
return [[k[0], k[1], d[k]] for k in d.keys()] # 转换成数组
p = [
[1, 3, 3],
[2, 4, 4],
[4, 5, 4],
[5, 6, 1]
]
print(shape(p))
结果:
new_pos: [[1, 2, 3], [2, 3, 3], [2, 3, 4], [3, 4, 4], [4, 5, 4], [5, 6, 1]]
dict: {(1, 2): 3, (2, 3): 4, (3, 4): 4, (4, 5): 4, (5, 6): 1}
result: [[1, 2, 3], [5, 6, 1], [2, 5, 4]]
利用字典唯一关键字的特性可以去重。map函数的可以很方便对列表和字典之间进行转换。