LeetCode 分类练习 Task04:查找2

这篇博客介绍了LeetCode中两种查找技巧:对撞指针和滑动数组结合二分查找。对撞指针主要用于处理有序数组中的重复值问题,而二分查找则提供了一个通用的代码模板,适用于各种情况,包括空区间、重复元素等。文中还包含相关练习题。
摘要由CSDN通过智能技术生成

一、查找——对撞指针

对撞指针套路:

# 对撞指针套路
l,r = 0, len(nums)-1
while l < r:
    if nums[l] + nums[r] == target:
        return nums[l],nums[r]
    elif nums[l] + nums[r] < target:
        l += 1
    else:
 	r -= 1

处理重复值的套路:先转换为有序数组,再循环判断其与上一次值是否重复:

# 对撞指针套路
l,r = 0, len(nums)-1
while l < r:
    sum = nums[i] + nums[l] + nums[r]
    if sum == target:
 	res.append([nums[i],nums[l],nums[r])
        l += 1
	r -= 1
        while l < r and nums[l] == nums[l-1]: l += 1
        while l < r and nums[r] == nums[r+1]: r -= 1
    elif sum < target:
        l += 1
    else:
 	r -= 1

练习 在这里插入图片描述

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]: 
	nums = list(enumerate(nums))
 	# 根据value来排序
 	nums.sort(key = lambda x:x[1])
 	l,r = 0, len(nums)-1
	while l < r:
 	if nums[l][1] + nums[r][1] == target:
   	    return nums[l][0],nums[r][0]
 	elif nums[l][1] + nums[r][1] < target:
	    l += 1
 	else:
 	    r -= 1

在这里插入图片描述

class Solution:
    def threeSum(self, nums: [int]) -> [[int]]:
	nums.sort()
	res = []
	for i in range(len(nums)-2):
 	    # 因为是排序好的数组,如果最小的都大于0可以直接排除
 	    if nums[i] > 0: break
	    # 排除i的重复值
 	    if i > 0 and nums[i] == nums[i-1]: continue
 	    l,r = i+1, len(nums)-1
 	    while l < r:
 		sum = nums[i] + nums[l] + nums[r]
 		if sum == 0:
 		    res.append([nums[i],nums[l],nums[r]])
		    l += 1
		    r -= 1
		    while l < r and nums[l] == nums[l-1]: l += 1
		    while l < r and nums[r] == nums[r+1]: r -= 1
 		elif sum < 0:
		    l += 1
		else:
		    r -= 1
 	return res

在这里插入图片描述

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
 	nums.sort()
 	res = []
 	if len(nums) < 4: return res
 	if len(nums) == 4 and sum(nums) == target:
	    res.append(nums)
    	    return res
 	for i in range(len(nums)-3):
 	    if i > 0 and nums[i] == nums[i-1]: continue
 	    for j in range(i+1,len(nums)-2):
 	        if j > i+1 and nums[j] == nums[j-1]: continue
 		l,r = j+1, len(nums)-1
	   	while l < r:
 		    sum_value = nums[i] + nums[j] + nums[l] + nums[r]
 		    if sum_value == target:
 			res.append([nums[i],nums[j],nums[l],nums[r]])
                        l += 1
	 		r -= 1
 			while l < r and nums[l] == nums[l-1]: l += 1
 			while l < r and nums[r] == nums[r+1]: r -= 1
 		    elif sum_value < target:
                        l += 1
 		    else:
 			r -= 1
        return res

在这里插入图片描述

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
 	nums.sort()
 	diff = abs(nums[0]+nums[1]+nums[2]-target)
 	res = nums[0] + nums[1] + nums[2]
 	for i in range(len(nums)):
 	    l,r = i+1,len(nums)-1
 	    t = target - nums[i]
	    while l < r:
 		if nums[l] + nums[r] == t:
   		    return nums[i] + t
 		else:
 		    if abs(nums[l]+nums[r]-t) < diff:
 			diff = abs(nums[l]+nums[r]-t)
   			res = nums[i]+nums[l]+nums[r]
 		    if nums[l]+nums[r] < t:
                        l += 1
 		    else:
 			r -= 1
        return res

在这里插入图片描述

class Solution:
    def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int:
 	from collections import Counter
  	record = Counter()
 	for i in range(len(A)):
 	    for j in range(len(B)):
 		record[A[i]+B[j]] += 1
        res = 0
 	for i in range(len(C)):
 	    for j in range(len(D)):
 		find_num = 0 - C[i] - D[j]
 		if record.get(find_num) != None:
	 	    res += record[find_num]
        return res 

在这里插入图片描述

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
 	from collections import defaultdict
 	strs_dict = defaultdict(list)
 	res = []
 	for str in strs:
	    key = ''.join(sorted(list(str)))
   	    strs_dict[key] += str.split(',')
 	for v in strs_dict.values():
 	    res.append(v)
 	return res

在这里插入图片描述

class Solution:
    def numberOfBoomerangs(self, points: List[List[int]]) -> int:
 	res = 0
 	from collections import Counter
 	for i in points:
 	    record = Counter()
 	    for j in points:
 		if i != j:
 		    record[self.dis(i,j)] += 1
 	    for k,v in record.items():
 		res += v*(v-1)
   	return res
    def dis(self,point1,point2):
 	return (point1[0]-point2[0]) ** 2 + (point1[1]-point2[1]) ** 2

在这里插入图片描述

class Solution:
    def maxPoints(self,points):
 	if len(points) <= 1:
 	    return len(points)
 	res = 0
 	from collections import defaultdict
 	for i in range(len(points)):
 	    record = defaultdict(int)
 	    samepoint = 0
 	    for j in range(len(points)):
 		if points[i][0] == points[j][0] and points[i][1] == points[j][1]:
 		    samepoint += 1
 		else:
 		    record[self.get_Slope(points,i,j)] += 1
 	    for v in record.values():
 		res = max(res, v+samepoint)
 	    res = max(res, samepoint)
   	return res
    def get_Slope(self,points,i,j):
 	if points[i][1] - points[j][1] == 0:
   	    return float('Inf')
 	else:
 	    return (points[i][0] - points[j][0]) / (points[i][1] - points[j][1])

二、查找——滑动数组&二分查找

二分查找代码模板:

class Solution:
    def firstBadVersion(self, arr):
 	# 第一点:lo和hi分别对应搜索的上界和下界,但不一定为0和arr最后一个元素的下标
 	lo, hi = 0, len(arr)-1
   	while lo < hi:
 	    # 第二点:因为Python没有溢出,int型不够了会自动改成long int型,所以无需担心
 	    # 可以把这一行改成:mid = lo + (hi-lo) // 2
 	    mid = (lo+hi) // 2# 第三点:比较重要的就是这个f(x),在带入模板的情况下,写对函数就完了
 	    if f(x):
 		lo = mid + 1
 	    else:
   		hi = mid
 	return lo

这种写法比较好的点在于:

  1. 即使区间为空、答案不存在、有重复元素、搜索开/闭区间的上/下界也同样适用
  2. ±1 的位置调整只出现了一次,而且最后返回lo还是hi都是对的,无需纠结

练习

在这里插入图片描述

class Solution:
    def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
 	record = set()
 	for i in range(len(nums)):
 	    if nums[i] in record:
 	    	return True
 	    record.add(nums[i])
 	    if len(record) == k+1:
   		record.remove(nums[i-k])
	return False

在这里插入图片描述

class Solution:
    def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
 	if t == 0 and len(nums) == len(set(nums)):
   	    return False
 	for i in range(len(nums)):
 	    for j in range(1,k+1):
 		if i+j >= len(nums): break
   		if abs(nums[i+j]-nums[i]) <= t: return True
 	return False
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值