解决之路= =
因为是周日,找个中等题挑战一下。
题目描述
测试案例(部分)
第一次
想一下,因为涉及到底乘高,所以不能排序。逆序也没必要。
简化一下题干,盛水最多,也就是算面积最大,其实就是挑两个下标不同的“板”,然后根据“木桶原理”,挑出最短的“板”,然后底边乘侧边算出面积。
然后想一下是否有可以减少次数的机会。挑两个“板”就能想到两次循环,时间复杂度O(n²)
。然后,很容易想到,下标为0
和1
的两个“板”和下标1
和0
的两个“板”情况是一样的,所以每轮循环只需要检测后面的下标就行,不需要检测前面的。
虽然说这样时间复杂度没变(n-1 + n-2 + ... + 1=(n-1)n/2 => 还是O(n²)
),但是循环次数还是少了一些的。暂时没有想到其他更好的解法了,先暴力解出来。
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
area = []
n = len(height)
# 双循环找“板”
for k, v in enumerate(height):
for i in range(k+1, n):
# 木桶原理,取最小
h = min(v, height[i])
# 面积算出来就追加到列表
area.append((i - k) * h)
# 列表最大值返回
return max(area)
测试正确,提交试试。果然,第一次不过原则。
第二次
报错原因是超时,是因为输入的案例数据太大了,自己的代码虽然刻意减少了次数,但是时间复杂度还是O(n²)
,所以面对大量数据,花费的时间还是没有降下来。
想一想还有什么方法,最好是通过一重循环就可以解决问题。感觉用双指针前后夹出最大面积,但感觉不管通过什么办法去减少花费时间,最后都要算出所有两两搭配出的面积。算每种两两搭配的组合,肯定需要O(n²)
的时间复杂度。。。。
看看万能的评论区吧。评论区都在说双指针法,但没有看到之前有人整理的多语言的实现总结,翻了很多,java实现或者c还是多。
看到一个老哥总结成了一句话,“较矮的一边向中间收缩寻找更大的容积,直到相遇”
看到这话,感觉很有道理。自己再来试着先不看他的代码,顺着这句话的思路实现一下。
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
n = len(height)
left = 0
right = n-1
area = []
while left < right:
area.append((right - left) * min(height[left], height[right]))
# 哪边小,哪边移动。等于号无所谓,左右随便一个移动。
if height[left] < height[right]:
left += 1
elif height[left] >= height[right]:
right -= 1
return max(area)
提交成功。
确实,双指针法可以帮助在O(n)
的情况下算出最大面积的匹配。
之前以为双指针法只能在有序序列的情况下进行,所以没太多考虑到双指针法。自己一开始想到双指针法,也因为感觉双指针法还是需要遍历所有两两搭配出的面积。
但是自己没有想到,虽然双指针法还是需要遍历所有两两搭配出的面积,但是只用了一个循环就可以实现遍历所有两两搭配。以后遇到无序序列,只要感觉可能能用就用双指针法试试。
附件
每日打卡以后再加上背单词打卡,每天积累一点点。