本文主要记录学习python中遇到的有趣的例题,本例题主要来自leetcode。原题如下:
"""给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。"""
接下来主要分享个人解题过程:
题目分析
面对这个问题,首先可以做一个草图便于分析:
从图中可以了解到:最高的柱可以与任意次高的柱形成“水坑”从而达到蓄水的作用,所以可以以最高柱为中心,将柱群分为左右两个部分分别分析。最高与次高之间的间距与次高的高为最大蓄水量,而中间的其他柱体主要侵占了蓄水空间,所以思路为用最大蓄水量减去中间柱体的高度,即为实际蓄水量。此后将本部分的次高柱变成下一次分析的最高柱,次高柱到一端所有柱位下一个需要分析的部分,然后在该部分中重复以上内容。
算法流程图:
算法主要包含划分柱状群,判断是否构成“水坑”,计算面积,绘制可视化图像几个部分。算法流程图如下所示:
代码部分:
切分柱状群
本解题方式最核心的部分就是如何正确的切分出每一个块,并且在后续出现相同柱群的时候,然后正确区分它们的索引(该部分本文做得很繁琐,如果有简单的想法欢迎交流)。本文中解决前后出现相同柱群导致的索引出现错误从而导致绘图出错的解决办法是通过设置tag_area变量存储每一个索引序号用于后续的绘图操作(PS:过程中遇到的问题包括丢数,数据索引错误等)。
def cut_part(part, val_ser=None, all_part=None, limit=1):
global Area, tag_area
max_1 = np.amax(part)
max_index = np.argmax(part)
Area += max_index*max_1
area_1 = part[0:max_index]
area_2 = [max_1 - i for i in area_1]
tag_key = find_key(val_ser, part[0])
print("\n", "Carry out a cut_part", "\n",
"The starting value of this section may be:", tag_key,
"The maximum index of this section is:{:^10d}".format(max_index),
"The maximum value is:{:^10d}".format(max_1), "The length of this section is:{:^10d}".format(len(area_1)))
if len(area_1) == 0:
for key in tag_key:
judgment = 1
print("This part is monotonous and cannot hold water")
if key == tag_area[-1][0]+limit or key == tag_area[0][0]+limit:
for key_1, value_1 in tag_area:
if key_1 == key:
judgment = 0
break
if judgment == 1:
tag_area = tag_area + [(key, 0)]
print("The maximum index of this section is:{:^10d}".format(key))
if max_index != len(part) - 1:
return cut_part(part[max_index + 1::], val_ser=Val_ser, all_part=Value, limit=limit)
else:
area_x = []
for key in tag_key:
area_x = []
for i in range(len(area_1)):
judgment = 1
if area_1[i] == all_part[key+i*limit]:
for key_1, value_1 in tag_area:
if key_1 == key:
judgment = 0
break
if judgment == 1:
area_x.append(key+i*limit)
else:
break
if len(area_x) == len(area_1):
tag_key.append(key)
print("This section actually starts with the bit:{:^10d}".format(key))
break
for value in area_1:
Area -= value
tag_area = tag_area + list(zip(area_x, area_2)) + [(tag_key[-1]+limit*len(area_1), 0)]
print("The segmentation area of this part is:", tag_area[-len(area_x)-1:-1:1], "\n", "The index is:", area_x)
if max_index != len(part)-1:
return cut_part(part[max_index+1::], val_ser=Val_ser, all_part=Value, limit=limit)
return 0
最后一个定义函数部分使用Matplotlib绘图库中bar函数绘制柱状图做数据可视化:
def paint_draw(index, sour, area):
# 本部分主要用于图像中中文部分展示
font = dict(family='KaiTi',
weight='bold',
size='10')
plt.rc('font', **font)
plt.rc('axes', unicode_minus=False)
fig, ax = plt.subplots()
# index为步长索引,sour为柱状图高度,area为每个柱上蓄水高度
ax.bar(index, sour, width=1, color="peru", edgecolor="gray", linewidth=0.7)
ax.bar(index, area, bottom=sour, width=1, color="cyan", edgecolor="white", linewidth=0.7)
for a, b in zip(index, sour):
plt.text(a, b, '%d' % b, ha='center', va='bottom', color="orange", fontsize=7)
for a in range(len(area)):
if area[a] != 0:
plt.text(index[a], (sour[a]+area[a]), '%d' % area[a], ha='center', va='bottom', color="blue", fontsize=7)
else:
continue
plt.show()
完整程序如下:
import numpy as np
import matplotlib.pyplot as plt
import time
def find_key(diction, tag_value) -> list:
tag_key = []
for key, value in diction.items():
if value == tag_value:
tag_key.append(key)
return tag_key
def sco_def():
pass
def cut_part(part, val_ser=None, all_part=None, limit=1):
global Area, tag_area
max_1 = np.amax(part)
max_index = np.argmax(part)
Area += max_index*max_1
area_1 = part[0:max_index]
area_2 = [max_1 - i for i in area_1]
tag_key = find_key(val_ser, part[0])
print("\n", "Carry out a cut_part", "\n",
"The starting value of this section may be:", tag_key,
"The maximum index of this section is:{:^10d}".format(max_index),
"The maximum value is:{:^10d}".format(max_1), "The length of this section is:{:^10d}".format(len(area_1)))
if len(area_1) == 0:
for key in tag_key:
judgment = 1
print("This part is monotonous and cannot hold water")
if key == tag_area[-1][0]+limit or key == tag_area[0][0]+limit:
for key_1, value_1 in tag_area:
if key_1 == key:
judgment = 0
break
if judgment == 1:
tag_area = tag_area + [(key, 0)]
print("The maximum index of this section is:{:^10d}".format(key))
if max_index != len(part) - 1:
return cut_part(part[max_index + 1::], val_ser=Val_ser, all_part=Value, limit=limit)
else:
area_x = []
for key in tag_key:
area_x = []
for i in range(len(area_1)):
judgment = 1
if area_1[i] == all_part[key+i*limit]:
for key_1, value_1 in tag_area:
if key_1 == key:
judgment = 0
break
if judgment == 1:
area_x.append(key+i*limit)
else:
break
if len(area_x) == len(area_1):
tag_key.append(key)
print("This section actually starts with the bit:{:^10d}".format(key))
break
for value in area_1:
Area -= value
tag_area = tag_area + list(zip(area_x, area_2)) + [(tag_key[-1]+limit*len(area_1), 0)]
print("The segmentation area of this part is:", tag_area[-len(area_x)-1:-1:1], "\n", "The index is:", area_x)
if max_index != len(part)-1:
return cut_part(part[max_index+1::], val_ser=Val_ser, all_part=Value, limit=limit)
return 0
def paint_draw(index, sour, area):
font = dict(family='KaiTi',
weight='bold',
size='10')
plt.rc('font', **font)
plt.rc('axes', unicode_minus=False)
fig, ax = plt.subplots()
ax.bar(index, sour, width=1, color="peru", edgecolor="gray", linewidth=0.7)
ax.bar(index, area, bottom=sour, width=1, color="cyan", edgecolor="white", linewidth=0.7)
for a, b in zip(index, sour):
plt.text(a, b, '%d' % b, ha='center', va='bottom', color="orange", fontsize=7)
for a in range(len(area)):
if area[a] != 0:
plt.text(index[a], (sour[a]+area[a]), '%d' % area[a], ha='center', va='bottom', color="blue", fontsize=7)
else:
continue
plt.show()
if __name__ == "__main__":
n = 1
while n:
time_1 = time.time()
num = eval(input("Please enter the number of random values:"))
np.random.seed(n)
Value = [np.random.randint(0, 100) for i in range(num)]
ser_num = np.arange(0, num)
Val_ser = dict(zip(ser_num, Value))
print("The generated random value is:", Value)
Area = 0
V_max_index = np.argmax(Value)
print("The maximum index is:", V_max_index, " The maximum is", np.amax(Value))
tag_area = [(V_max_index, 0)]
if V_max_index != 0:
part1 = Value[V_max_index-1::-1]
else:
part1 = []
part2 = Value[V_max_index+1::]
print("The part1 is: ", part1, " The part2 is: ", part2)
if np.size(part1) > 0:
print("\n", "*"*30, "start", "Run to the decreasing side", "start", "*"*30)
cut_part(part1, val_ser=Val_ser, all_part=Value, limit=-1)
if np.size(part2) > 0:
print("\n", "*"*30, "start", "Run to the increasing side", "start", "*"*30)
cut_part(part2, val_ser=Val_ser, all_part=Value)
Area_1 = sorted(tag_area, key=lambda x: x[0])
Area_list = []
for i in range(len(Area_1)):
Area_list.append(Area_1[i][1])
n = 1
if Area_1[i][0] == i + n:
print("Item {:^5d} is missing".format(i-1))
n += 1
elif Area_1[i][0] == i - n:
print("Item {:^5d} surplus".format(i-1))
n -= 1
else:
continue
print("The area of each part is", Area_1, len(Area_1))
print("The total area is", Area)
time_2 = time.time()
print("Service time:", time_2-time_1)
paint_draw(ser_num, Value, Area_list)
n = eval(input("Please enter a termination condition:"))
本程序运行结果图: