【刷题笔记】接雨水||暴力通过||符合思维方式

接雨水

文章目录

  • 接雨水
    • 1 题目描述
    • 2 分析
      • 2.1 左到右
      • 2.2 右到左
      • 2.3 计算面积
    • 3 代码
      • 3.1 Java
      • 3.2 Python
    • 附录1

1 题目描述

https://leetcode.cn/problems/trapping-rain-water/

面试的时候关键不是你的手法多么精妙,首先要做出来。

【刷题笔记】接雨水||暴力通过||符合思维方式_第1张图片

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

【刷题笔记】接雨水||暴力通过||符合思维方式_第2张图片

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

输入:height = [4,2,0,3,2,5]
输出:9


2 分析

通过观察,我们知道,要计算接的水,我们要找到能够存水的凹槽:

【刷题笔记】接雨水||暴力通过||符合思维方式_第3张图片

我们将这些存水的凹槽的边缘连接起来,可以发现,折线图的总体趋势是从低到高,从高到低(下图是随机生成的不同高度下的存水凹槽边缘图,以及其连线)

【刷题笔记】接雨水||暴力通过||符合思维方式_第4张图片

绘图代码已经在附录1中给出,可以直接运行,随机生成数据以及查看绘图。

那么我们能做的就是从左到右,依次找到越来越高的值;保存其索引,从右到左,依次找到越来越高的值,保存其索引。然后计算这些索引之间的最大盛水面积,减去之间的柱子的面积,就是最后的接雨水的结果

2.1 左到右

while start < len(height) and height[start] == 0: # 指针不断右移,跳过为0的元素
    start = start + 1
if start >= len(height) - 1: # 要是全为0,return 0
    return 0
lists.append(height[start]) # 保存值
indexes.append(start) # 保存索引
for i in range(start + 1, len(height)):
    if height[i] >= lists[-1]: # 比上一个凹槽边缘大或者等于,保存
        lists.append(height[i])
        indexes.append(i)

2.2 右到左

# 注意从右到左,不要超过左到右的边界indexes[-1],
 while end > indexes[-1] and height[end] == 0: 
        end = end - 1 
# 而且从左到右已经判断完全0了,接下来不用判断了
reverse_lists.append(height[end])
reverse_indexes.append(end)
for i in range(end - 1, indexes[-1] - 1, -1): # 从右到左,注意边界
# 注意range(end - 1, indexes[-1] - 1, -1),举个例子,如果要生成一个10~0的
# 序列,则为range(10, -1, -1),我们知道range的前两个参数为范围,前闭后开,[10,-1)
# 第二个-1为step,表示按照反向遍历。
    if height[i] >= reverse_lists[-1]:
        reverse_lists.append(height[i])
        reverse_indexes.append(i)

2.3 计算面积

最直接的想法是,直接分开计算面积:
【刷题笔记】接雨水||暴力通过||符合思维方式_第5张图片

l_res = 0
for i in range(1, len(lists)):
    l = indexes[i - 1]
    r = indexes[i]
    l_res = l_res + (r - l - 1) * (min(height[l], height[r])) # 高度最小值乘以长度,
    # 长度为(right - left - 1)
    for j in range(l + 1, r):
        l_res = l_res - height[j] # 减去中间的面积

for i in range(len(reverse_indexes) - 2, -1, -1): # 反过来遍历
    r = reverse_indexes[i]
    l = reverse_indexes[i + 1]
    l_res = l_res + (r - l - 1) * (min(height[l], height[r]))
    for j in range(l + 1, r):
        l_res = l_res - height[j]
return l_res

为了简单计算,首先我们将两个索引合并,

l_res = 0
# 将indexes和reversed(reverse_indexes)合并
indexes.extend(reversed(reverse_indexes))

在上面的图中,我们看到,两边的索引(左到右:[0, 3, 5],右到左:[19, 16, 11, 7, 5])有重叠,合并以后变成了[0, 3, 5, 5, 7, 11, 16, 19]怎么办?

无所谓,重叠之后长度为0,二者之间的面积还是0,不会对最终的面积有啥影响。

那么最后计算面积的过程为:

for i in range(1, len(indexes)):
    l = indexes[i - 1]
    r = indexes[i]
    l_res = l_res + max((r - l - 1), 0) * (min(height[l], height[r]))
    for j in range(l + 1, r):
        l_res = l_res - height[j]
return l_res

3 代码

3.1 Java

class Solution {

    public int trap(int[] height) {

        if (height.length <= 1) return 0;

        List<Integer> lists = new ArrayList<>();
        List<Integer> indexes = new ArrayList<>();

        List<Integer> reverse_lists = new ArrayList<>();
        List<Integer> reverse_indexes = new ArrayList<>();
        int start = 0;
        int end = height.length - 1;
        while(start < height.length && height[start] == 0) start++;
        if (start >= height.length - 1) return 0;
        lists.add(height[start]);
        indexes.add(start);

        for (int i = start + 1; i < height.length; i++) {
            if (height[i] >= lists.get(lists.size() - 1)) {
                lists.add(height[i]);
                indexes.add(i);
            }
        }
        int l_res = 0;
        for (int i = 1; i < lists.size(); i++) {
            int l = indexes.get(i - 1);
            int r = indexes.get(i);
            l_res += (r - l - 1) * (Math.min(height[l], height[r]));
            for (int j = l + 1; j < r; j++) {
                l_res -= height[j];
            }
        }


        while(end > indexes.get(indexes.size() - 1) && height[end] == 0) end--;
        reverse_lists.add(height[end]);
        reverse_indexes.add(end);
        for (int i = end - 1; i >= indexes.get(indexes.size() - 1); i--) {
            if (height[i] >= reverse_lists.get(reverse_lists.size() - 1)) {
                reverse_lists.add(height[i]);
                reverse_indexes.add(i);
            }
        }

        for (int i = reverse_indexes.size() - 2; i >=0; i--) {
            int r = reverse_indexes.get(i);
            int l = reverse_indexes.get(i + 1);
            l_res += (r - l - 1) * (Math.min(height[l], height[r]));
            for (int j = l + 1; j < r; j++) {
                l_res -= height[j];
            }
        }
        return l_res;

    }
}

3.2 Python

class Solution(object):

    # python 代码
    def trap(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        if len(height) <= 1:
            return 0
        lists = []
        indexes = []
        reverse_lists = []
        reverse_indexes = []
        start = 0
        end = len(height) - 1
        while start < len(height) and height[start] == 0:
            start = start + 1
        if start >= len(height) - 1:
            return 0
        lists.append(height[start])
        indexes.append(start)
        for i in range(start + 1, len(height)):
            if height[i] >= lists[-1]:
                lists.append(height[i])
                indexes.append(i)
        while end > indexes[-1] and height[end] == 0:
            end = end - 1
        reverse_lists.append(height[end])
        reverse_indexes.append(end)
        for i in range(end - 1, indexes[-1] - 1, -1):
            if height[i] >= reverse_lists[-1]:
                reverse_lists.append(height[i])
                reverse_indexes.append(i)
        l_res = 0
        # 将indexes和reversed(reverse_indexes)合并
        indexes.extend(reversed(reverse_indexes))
        for i in range(1, len(indexes)):
            l = indexes[i - 1]
            r = indexes[i]
            l_res = l_res + max((r - l - 1), 0) * (min(height[l], height[r]))
            for j in range(l + 1, r):
                l_res = l_res - height[j]
        return l_res

在这里插入图片描述

附录1

# python 代码
def trap(height):
    """
    :type height: List[int]
    :rtype: int
    """
    if len(height) <= 1:
        return 0
    lists = []
    indexes = []
    reverse_lists = []
    reverse_indexes = []
    start = 0
    end = len(height) - 1
    while start < len(height) and height[start] == 0:
        start = start + 1
    if start >= len(height) - 1:
        return 0
    lists.append(height[start])
    indexes.append(start)
    for i in range(start + 1, len(height)):
        if height[i] >= lists[-1]:
            lists.append(height[i])
            indexes.append(i)
    while end > indexes[-1] and height[end] == 0:
        end = end - 1
    reverse_lists.append(height[end])
    reverse_indexes.append(end)
    for i in range(end - 1, indexes[-1] - 1, -1):
        if height[i] >= reverse_lists[-1]:
            reverse_lists.append(height[i])
            reverse_indexes.append(i)
    l_res = 0
    # 将indexes和reversed(reverse_indexes)合并
    history_indexes = indexes.copy()
    indexes.extend(reversed(reverse_indexes))
    for i in range(1, len(indexes)):
        l = indexes[i - 1]
        r = indexes[i]
        l_res = l_res + max((r - l - 1), 0) * (min(height[l], height[r]))
        for j in range(l + 1, r):
            l_res = l_res - height[j]
    return l_res, history_indexes, reverse_indexes


def draw_pic(water, indexes, reverse_indexes):
    indexes.extend(reverse_indexes)
    indexes = list(set(indexes))
    indexes.sort()
    # 绘制折线图,x轴为indexes,y轴为water[indexes]
    plt.plot(indexes, [water[i] for i in indexes])
    plt.scatter(indexes, [water[i] for i in indexes])

    # 将water绘制成柱状图
    plt.bar(range(len(water)), water, color='yellow', zorder=1, edgecolor='black', linewidth=1)
    # 将indexes绘制成柱状图,绿色
    plt.bar(indexes, [water[i] for i in indexes], color='g', zorder=100, edgecolor='black', linewidth=1)
    # 设置 x 轴刻度及标签
    plt.xticks(np.arange(0, 20), range(0, 20))
    plt.show()

# 生成一个更长的测试用例
import random
random.randint(0, 10)
water = [random.randint(0, 10) for _ in range(20)]

res = trap(water)
indexes = res[1]
reverse_indexes = res[2]
draw_pic(water, indexes, reverse_indexes)

你可能感兴趣的:(算法,笔记,算法,数组)