15 - 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
ans = []
n = len(nums)
for p1 in range(n):
if p1 > 0 and nums[p1] == nums[p1-1]:
continue
p3 = n-1
for p2 in range(p1+1,n):
if p2 > p1+1 and nums[p2] == nums[p2-1]:
continue
while p2 < p3 and nums[p2] + nums[p3] > -nums[p1]:
p3 -= 1
if p2 == p3:
break
if nums[p2] + nums[p3] == -nums[p1]:
ans.append([nums[p1], nums[p2], nums[p3]])
return ans
完全参考了官方解法:三数之和
最开始只能想到暴力,
O
(
n
3
)
O(n^3)
O(n3),看了题解get了排序+双指针,把第二和第三重循环糅合到一块。
这题要注意避免重复,通过排序可以避免[a,b,c],[b,a,c],[c,b,a]…这类情况出现,此外排序后的列表利用if p1 > 0 and nums[p1] == nums[p1-1]
也可以避免重复数字重复计算
最终的时间复杂度为
O
(
n
2
)
O(n^2)
O(n2),空间复杂度为
O
(
1
)
O(1)
O(1)
其实代码都不是一步就写得好的,都是慢慢优化来的,可以逐渐在最容易想到的方法上优化。
11 - 盛最多水的容器
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。
class Solution:
def maxArea(self, height: List[int]) -> int:
p1, p2 = 0, len(height)-1
ans = (p2 - p1) * min(height[p1], height[p2])
while p1 < p2:
temp = (p2 - p1) * min(height[p1], height[p2])
if temp > ans:
ans = temp
if height[p1] < height[p2]:
p1 += 1
else:
p2 -= 1
return ans
又是看官方答案才写出来的,我为什么只能想到暴力。。。盛最多水的容器
这题我感觉考的是分析,双指针这个方法只是手段。最重要的是要分析出规律,比如
- 为什么两个指针要设在列表头尾,其他位置不行吗?
这样做是为了保证顺序,因为从两边向中间遍历时,p2-p1的值是减小的,这样结合移动值小的指针,就可以保证 O ( n ) O(n) O(n)时间内找到最优解 - 为什么每次移动的是值小的指针?
反过来想,若移动值较大的指针,min(height[p1], height[p2])不会有什么改善甚至更糟,p2-p1也变得更小了,毫无疑问不会有什么改善,所以只能移动值较小的指针看看会不会有突破
上面两点分析使得直接可以去掉一重循环。
我发现双指针在趣掉多余的循环上很有帮助,但更重要的是分析。
14 - 最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 “”。
0 <= strs.length <= 200
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
if not strs:
return ''
maxStr = strs[0]
for s in strs:
temp = ''
for j in range(min(len(s),len(maxStr))):
if s[j] == maxStr[j]:
temp += maxStr[j]
else:
break
maxStr = temp
return maxStr
依次扫描字符串列表的每一项,维护一个maxStr记录当前最大公共前缀,每次用新的字符串和maxStr比较并更新maxStr。当扫描完整个列表,即得到答案。