原创@b站灵茶山艾府
有序数组,左指针l,右指针r
力扣167 两数之和II-输入有序数组
题目描述:给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
l, r = 0, len(numbers) - 1
while numbers[l] + numbers[r] != target:
if numbers[l] + numbers[r] > target:
r -= 1
else:
l += 1
return [l + 1, r + 1]
力扣15 三数之和
题目描述:给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为 0
且不重复的三元组。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 解析题目:给出一个数组,返回一个含有多个三元组的数组
# 如何利用上次的相向双指针的思想?
# 这道题是否存在暴力解法,如何在暴力解法上进行优化?
# 三元组的顺序不重要,所以可以先进行排序
# i < j < k
# 设定nums[i],寻找另外两个数相加等于-nums[i]
# 不可以包含重复的三元组
nums.sort()
ans = []
n = len(nums)
for i in range(n - 2):
# 为啥那么这里i要>0,哦哦哦不大于零一开始就会报错
# 这里用continue而不是用while循环让i往后走,因为下次进入for循环i还是会按照顺序来
if i > 0 and nums[i] == nums[i - 1]:
continue
# 细节优化
# 我的问题是,这个思想能不能直接在下面的循环里体现出来呢
# break是跳出当前循环直接终止,continue是跳过这一次进入下一次
if nums[i] + nums[i + 1] + nums[i + 2] > 0:
break
if nums[i] + nums[n - 1] + nums[n - 2] < 0:
continue
j = i + 1
k = n - 1
while j < k:
s = nums[i] + nums[j] + nums[k]
if s < 0:
j += 1
elif s > 0:
k -= 1
else:
ans.append([nums[i], nums[j], nums[k]])
# 这里注意是和前一个值比较,而不是和他的后一个值比较
j += 1
while j < k and nums[j] == nums[j - 1] :
j += 1
k -= 1
while j < k and nums[k] == nums[k + 1]:
k -= 1
return ans
力扣11 盛最多水的容器
题目描述:
给定一个长度为 n
的整数数组 height
。有 n
条垂线,第 i
条线的两个端点是 (i, 0)
和 (i, height[i])
。
找出其中的两条线,使得它们与 x
轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
class Solution:
def maxArea(self, height: List[int]) -> int:
# 时间复杂度O(n) 空间复杂度O(1)
# 问题的关键在于理清逻辑,对于一个矮一些的边,只要更接近就会变小,在变近的过程中,只有更高的边才有可能出现更大的值,所以可以直接舍弃当前值
ans = 0
left = 0
right = len(height) - 1
while left < right:
area = (right - left) * min(height[right], height[left])
ans = max(ans, area)
if height[right] > height[left]:
left += 1
else:
right -= 1
return ans
力扣42 接雨水
题目描述:给定 n
个非负整数表示每个宽度为 1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
class Solution:
def trap(self, height: List[int]) -> int:
# 方法一:前后缀分解,维护两个数组,分别存储前缀后缀最大值
# 时间复杂度O(n)空间复杂度O(n)
# n = len(height)
# ans = 0
# pre_max = [0] * n
# pre_max[0] = height[0]
# for i in range(1, n):
# pre_max[i] = max(height[i], pre_max[i - 1])
# suf_max = [0] * n
# suf_max[n - 1] = height[n - 1]
# for i in range(n - 2, -1, -1): # 从n-2倒序枚举到0
# suf_max[i] = max(height[i], suf_max[i + 1])
# for h, pre, suf in zip(height, pre_max, suf_max):
# ans += min(pre, suf) - h
# return ans
# 方法二:相向双指针法
# 时间复杂度O(n) 空间复杂度O(1)
n = len(height)
left = 0
right = n - 1
pre_max = 0
suf_max = 0
ans = 0
while left <= right:
pre_max = max(height[left], pre_max)
suf_max = max(height[right], suf_max)
if pre_max > suf_max:
ans += suf_max - height[right]
right -= 1
else:
ans += pre_max - height[left]
left += 1
return ans