leetcode专题训练 42. Trapping Rain Water

1.动态编程法:按列填充方法。从左到右扫描数组,找到每个位置i只看左墙能接受的最高高度left_max[i]。再从右向左扫描数组,找到每个位置i只看右墙能接受的最高高度right_max[i]。在扫右墙能接受的最高高度时,就可以按列求出当前位置i能盛的最高水位的水了,最高水位的水是min(left_max[i], right_max[i])-height[i],也就是i位置能盛水的最高高度减去当前位置被墙挡住不能盛水的高度。
2.栈法:这个是按行填充的算法。大致就是维护一个栈,栈中的数字是左墙位置索引,然后一直找右墙并填充左墙与右墙之间的洼地。
往右遍历数组,如果
1)当前位置i墙高小于或等于栈顶墙高,那么就说明这个右墙不够高,不能够和左墙形成一个洼地来盛水,就把当前高度也压入栈,当成左墙。
2)当前位置i墙高大于栈顶墙高,那么就说明当前位置i可以与栈顶的左边一块墙形成一个洼地,然后把左边一块墙当作左墙,当前位置墙当作右墙,把洼地全部填入水。能盛distance*h的水,其中distance是当前位置i与栈顶左边一块墙之间所相隔的距离,也就是能填多少列h高度的水,h是min(height[i], height[st.top()-1])-height[st.top()],也就是具体能填多高的水。弹出栈顶。一直循环把当前位置i与栈顶比较,如果栈不为空且一直符合栈顶墙高小于当前位置i墙高,就一直重复此操作,否则把当前位置i的索引加入栈,并退出循环。
再开始继续向右遍历数组。并把当前位置i与栈顶比较,根据比较结果进行1)或2)操作。
3.双指指针法:这个也是一种按列填充方法。与第一种方法不同的是,这种方法用了双指针的技巧,就可以不用扫两次数组了,直接扫一次数组,并保存left_max和right_max两个变量,就可以按列填好水。具体方法如下。

class Solution:
    def trap(self, height: List[int]) -> int:
    	# 左指针l_ind的初始索引为0,右指针r_ind的初始索引为len(height)-1。
        l_ind = 0
        r_ind = len(height)-1
        left_max = 0
        right_max = 0
        ans = 0
        while l_ind < r_ind:
        	# 如果左指针位置的高度小于等于右指针位置的高度,那么就说明左指针位置的墙可以被当作
        	# 左墙,可以在左右指针之间位置填充小于或等于左指针位置高度的水,而不用担心右墙,反
        	# 之亦然。由于要处理最后一块洼地,也就是左右指针遍历时所得到的最后一块洼地,所以在
        	# 更新左右指针位置的时候,一直要将高度小的指针位置前进一位。
            if height[l_ind] <= height[r_ind]:
            	# 如果当前位置墙高大于左边最高的墙高,那么就说明,之后的所有洼地都可以按照当
            	# 前位置高度考虑填充水,也就是更新最高墙高
                if height[l_ind]>=left_max:
                    left_max = height[l_ind]
                # 否则就说明当前位置水位可以填充到与左墙高度相当。(此时需要注意到,就如前面
                # 所说,由于指针更新方式,此时右墙的最高高度一定会高于左墙,所以不用担心右墙)
                else:
                    ans += left_max-height[l_ind]
                l_ind += 1
            else:
                if height[r_ind]>=right_max:
                    right_max= height[r_ind]
                else:
                    ans += right_max-height[r_ind]
                r_ind -= 1
        return ans
发布了201 篇原创文章 · 获赞 26 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/Ema1997/article/details/100354035