11. 盛最多水的容器 - 力扣(LeetCode) (leetcode-cn.com)
借助本题来学习下双指针的用法和贪心算法
贪心算法:
在对问题求解的时候,总是做出当前看来是最好的选择,也就是说,仅仅考虑局部最优解,来组成最终的最优解
使用的前提条件是确定当前题目的每一步的局部最优解能换来最终的最优解,即要知道什么时候可以贪,什么时候不能贪
无法确定的时候往往需要进行数学证明来验证最后得到的是最优解
双指针:
顾名思义,就是利用两个指针去遍历数组,一般来说,遍历数组采用的是单指针(index)去遍历,两个指针一般是在有序数组中使用,一个放首,一个放尾,同时向中间遍历,直到两个指针相交,完成遍历,时间复杂度也是O(n)。
双指针又分为快慢指针和对撞指针 本题用到的是对撞指针,当遇到有序数组时,应该优先想到双指针来解决问题,因两个指针的同时遍历会减少空间复杂度和时间复杂度。
思路:
1.左指针从第一个开始向右移动,右指针从最后一个开始向左移动
2.设置初始答案为右指针左指针所指的值的最小值乘以左右指针的距离(盛水的area)
3. 移动左右指针当中对应数值较小的那一个来寻求局部最优解(证明附后)
4.比较当前解和之前的解的大小,储存较大的那个作为新解
5.返回第三步,直到左右指针相撞
6.返回解
伪证明:
假设左右指针分别对应的值是x, y且x<=y那么且距离为s,此时面积area为s*min(x, y)。当保证最小值不变的情况下移动右指针的时候,由于x不变,且s变小,所以area最大不会超过原来的area,所以要移动较小的那个值的指针
代码部分:
class Solution:
def maxArea(self, height: List[int]) -> int:
# 经典双指针
lk, rk = 0, len(height) - 1
ans = (rk - lk) * min(height[rk], height[lk])
while lk != rk:
if height[lk] >= height[rk]:
rk -= 1
ans = max(ans, (rk - lk) * min(height[rk], height[lk]))
else:
lk += 1
ans = max(ans, (rk - lk) * min(height[rk], height[lk]))
return ans
感觉还有优化空间,以后有机会改
坚持 共勉