接雨水问题——python学习过程记录

本文详细描述了解决LeetCode上的雨水接集问题的Python算法,通过递归切分柱状群,计算并减去中间柱体高度来确定蓄水量。同时,文章包含了代码实现和Matplotlib进行数据可视化的步骤。
摘要由CSDN通过智能技术生成

 本文主要记录学习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:"))

本程序运行结果图:

  • 14
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值