> 文档中心 > Python每日一练-----通过简单盛水问题了解省时省力的指针,动态规划

Python每日一练-----通过简单盛水问题了解省时省力的指针,动态规划

(第六天)昨天搬砖,今天盛水。

题目:

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。(你不能倾斜容器。)

示例

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

  • n == height.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 104

题目分析:求最大盛水量就是求最大的矩形面积。矩形的宽就是两竖直边的距离假设第一条是i,第二条是i+j,宽就是i+j-i=j,矩形的高就是min(height[i],height[i+j])所盛水的高度取决于最低的那块板。面积s=j*min(height[i],height[i+j])。min()为python内置函数,表示取最小值。

先来正常做法,暴力解题

def maxArea(height):    max = 0    # 初始化最大容积    for i in range(len(height)):      # 左边的容器边 for j in range(1, len(height)):   # 右边的容器边     if i + j = height[i]:   # 取两容器边最短的边      s = j * height[i]# 求面积  else:      s = j * height[i+j]  if s > max:    # 如果新的面积大于之前的最大面积,将最大面积的值换做为s      max = s return max

注意面积s=j*min(height[i],height[i+j])而不是s=j*abs(height[i] - height[i+j]),abs()是python内置函数表示取绝对值。第二个if语句可以使用min()函数替换。

def maxArea(height):    max = 0    # 初始化最大容积    for i in range(len(height)):      # 左边的容器边 for j in range(1, len(height)):   # 右边的容器边     if i + j  max:    # 如果新的面积大于之前的最大面积,将最大面积的值换做为s      max = s return max

这种暴力解题简单粗暴,但是只要height的列表长度足够长,所花的时间为O(n^2),就会运行得很慢。比如这样的长列表

计算速度比较慢。下面介绍速度比较快的指针算法。

我们可以假设height首位各有一条指针x,y。

当指针x对应的高度小于y对应的高度时,指针x向右移动1(x += 1)。

当指针y对应的高度小于x对应的高度时,指针y向左移动1(y -= 1)。

如果指针y对应的高度等于x对应的高度时,随意移动一个指针。

不断重复这一过程直到x与y重合。

以题目为例:

开始x,y位于首尾。x对应高度为1,y对应高度为7,面积s=1*8=8

接着1<7,指针x向右移动1,此时x对应高度为8,面积s=7*7=49

接着8>7,指针y向左移动1,以此类推。

那么问题来了,为什么要这么移动呢,为什么移动较低的指针而不是交高的指针?从感觉上我们可以知道,移动指针会使两指针之间的距离变小,意为着矩形的宽变小。这时移动对应高度最低的指针到下一个位置它对应的高度可能变高,可以弥补宽度变小。但是移动指针到下一位置对应高度也可能变小。

现在我们可以设 x<=y ,两指针间距离为 t,h(y),h(x)表示x,y指针对应的高度。

 那么对应的面积为 s=min[h(y), h(x)]*t.

移动y指针:这时我们可以肯定的是y指针无论怎么移动,新面积s1始终会小于s。因为y的移动有两种情况,

1.h(y)变大,那么h(y)仍大于h(x),  min[h(y), h(x)],取得的依然是h(x).然而t减小,所以s1<s

2.h(y)变小,h(y)<h(x),这时min[h(y), h(x)]取得h(y),对应高度减小,且t减小,所以s1<s

移动x指针:

设x指针对应新高度为h(x1),新距离为t1,这时 s=min[h(y), h(x)]*t <=  s=min[h(y), h(x1)]*t1

1.当h(x1) > h(x)时,min[h(y), h(x)] =  min[h(y), h(x1)]

2.当h(x1) =  min[h(y), h(x1)]

因为    t1<t

 所以必有             s=min[h(y), h(x)]*t <  s=min[h(y), h(x1)]*t1

证明完,我们用代码实现

def maxArea(height):x = 0      # 开始时的头指针y = len(height) - 1      # 尾指针s = 0     # 初始化面积while x < y:      # 限制条件,当x,y指针重合时停止    area = min(height[x], height[y]) * (y - x) # 取对应高度最小值    s = max(s, area)     # 比较新旧面积,取最大面积    if height[x] <= height[y]:    # 根据对应高度移动指针 x += 1    else: y -= 1return s      # 返回面积

这样的算法花费时间为O(n)。比O(n^2)省时多了。

来源参考:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/container-with-most-water/solution/sheng-zui-duo-shui-de-rong-qi-by-leetcode-solution/

房贷之家