class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
#相向指针
right = len(numbers) - 1
left = 0
s = 0
while left < right:
s = numbers[right] + numbers[left]
if s < target:
left += 1
elif s > target:
right -= 1
else:
return [left+1,right+1]
保证不重复的思路:如果当前值和前一个值相同,就跳过。
class Solution:
def twoSum(self,nums,target):
left = 0
right = len(nums) - 1
s = 0
ans = []
while left < right:
s = nums[right] + nums[left]
if s < target:
left += 1
elif s > target:
right -= 1
else:
ans.append([nums[left],nums[right]])
left += 1
while left < right and nums[left] == nums[left-1]:
left += 1
right -= 1
while left < right and nums[right] == nums[right+1]:
right -= 1
return ans
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
ans = []
for i in range(len(nums)-2):
if nums[i] + nums[i+1] + nums[i+2] > 0:
break #如果当前值加上比他大一点点的值就大于0,那就没有元组和为0 了
if nums[i] + nums[-1] + nums[-2] < 0:
continue #如果当前值和最后两个数加起来都比0小,就跳过当前值
target = 0 - nums[i]
if i > 0 and nums[i] == nums[i-1]:
continue
a = self.twoSum(nums[i+1:],target)
for j in a:
j.insert(0,nums[i])
ans.append(j)
return ans
思路还是,先找两个数的和与目标值相差最小,然后在遍历第三个数。
class Solution:
def twoSumClosest(self,nums,key):
left = 0
right = len(nums) - 1
ans = inf #用来衡量当前与目标的差距
s = 0
answer = inf #最后输出的和
while left < right:
s = nums[left] + nums[right]
if s < key:
if abs(key-s) < ans: #如果当前差距比记录中的小
answer = s #更改答案值
ans = abs(key-s) #更改差距
left += 1
elif s > key:
if abs(key-s) < ans:
answer = s
ans = abs(key-s)
right -= 1
else:
answer = key
break
return answer
def threeSumClosest(self, nums, target) -> int:
nums.sort()
ans = inf
answer = inf
for i in range(len(nums)-2):
key = target - nums[i]
a = self.twoSumClosest(nums[i+1:],key)
if abs(target-a-nums[i]) < ans:
answer = a + nums[i] #更改答案
ans = abs(target-a-nums[i]) #更改与目标的差距
return answer
思路就是套娃:四数之和就调用三数之和,三数之和调用两数之和,然后注意优化一下时间,以及判断数组的长度,以及当前元素和前一个重复的时候跳过。
class Solution:
def twoSum(self,nums,key):
left = 0
right = len(nums) - 1
s = 0
ans = []
while left < right:
s = nums[left] + nums[right]
if s < key:
left += 1
elif s > key:
right -= 1
else:
ans.append([nums[left],nums[right]])
left += 1
while left < right and nums[left] == nums[left-1]:
left += 1
right -= 1
while left < right and nums[right] == nums[right+1]:
right -= 1
return ans
def threeSum(self,nums,key):
ans = []
for i in range(len(nums)-2):
if nums[i] + nums[i+1] + nums[i+2] > key:
break
if nums[i] + nums[-1] + nums[-2] < key:
continue
if i > 0 and nums[i] == nums[i-1]:
continue
target = key - nums[i]
a = self.twoSum(nums[i+1:],target)
for j in a:
j.insert(0,nums[i])
ans.append(j)
return ans
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
ans = []
if len(nums) < 4:
return []
for i in range(len(nums)-3):
if nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target:
break
if nums[i] + nums[-1] + nums[-2] + nums[-3] < target:
continue
if i > 0 and nums[i] == nums[i-1]:
continue
key = target - nums[i]
b = self.threeSum(nums[i+1:],key)
for j in b:
j.insert(0,nums[i])
ans.append(j)
return ans
思路:遍历最大边,只要剩下的两边和大于最大边,就可以得到一个三角形。固定right找到能够大于target的最小left之后,right-left中的全部数值都可以大于target。然后左移right,重新寻找最小left。
class Solution:
def sumNumber(self,nums,target):#两边之和,要大于tartget
left = 0
right = len(nums) - 1
s = 0
ans = 0
while left < right:
s = nums[left] + nums[right]
if s <= target:
left += 1 #寻找left
else:
ans += right - left # right-left中的全部数值都可以大于target
right -= 1 #左移right,继续寻找left
return ans
def triangleNumber(self, nums) -> int:
#任意两边之和大于第三边,任意两边之差小于第三边
#题目中没有要求唯一,可重复
ans = 0
nums.sort()
if len(nums) < 3 or max(nums) == 0: #做特殊值判断
return 0
i = len(nums) - 1 #重最大的值开始遍历
while i > 1:
a = self.sumNumber(nums[:i],nums[i])
ans += a
i -= 1
return ans
思路: 从两边开始移动指针,每次计算一下当前的面积和答案比较,将最大值赋给答案,并且移动高度较小的指针。
class Solution:
def maxArea(self, height: List[int]) -> int:
#哪条线短就移动哪一条
left = 0
right = len(height) - 1
ans = 0
while left < right:
area = (right - left)*min(height[left],height[right])
ans = max(ans,area) #更新答案
if height[left] <= height[right]: #移动指针
left += 1
else:
right -= 1
return ans
思路(运行时间长):假设每个宽度是1的位置上都有一个桶,桶的高度由左右两边的最大高度决定。用桶的高度减去当前位置的高度,就可以得到接水的单位。
首先遍历一次数组,获得前缀最大值,然后倒序遍历一次数组,获得后序最大值。然后用p和s的最小值减去当前高度,就是接水值。
class Solution:
def trap(self, height) -> int:
premax = [height[0]] #前缀最大
lastmax = [height[-1]] #后序最大
ans = 0
for i in height[1:]:
premax.append(max(i,max(premax)))
for j in range(len(height) - 2,-1,-1):
lastmax.append(max(height[j],max(lastmax)))
lastmax = lastmax[::-1] #反转
for i in range(len(height)):
ans += abs(height[i] - min(premax[i],lastmax[i]))
return ans
思路(将空间复杂度改成O1):我们存下当前的最大前缀高度,以及当前的最大后缀高度,如果在某个位置,前缀小于后缀,那他当前能存的水就是前缀-高度,然后移动前缀,如果后缀小,就移动后缀。
class Solution:
def trap(self, height) -> int:
left = 0
right = len(height) - 1
premax = height[0]
lastmax = height[-1]
ans = 0
while left < right:
premax = max(premax,height[left]) #存下当前的最大前缀高度
lastmax = max(lastmax,height[right]) #当前的最大后缀高度
if premax < lastmax: #前缀小于后缀,移动前缀
ans += premax - height[left]
left += 1
else:
ans += lastmax - height[right]
right -= 1
return ans