# Leetcode - 搜索2

mhxin

## 1. 两数之和


def twoSum(nums: List[int], target: int) -> List[int]:
if not nums or len(nums) < 2:
return
prefix_sum = {}

n = len(nums)

for i in range(n):
if nums[i] in prefix_sum:
return [prefix_sum[nums[i]], i]

prefix_sum[target-nums[i]] = i

## 15. 三数之和

[
[-1, 0, 1],
[-1, -1, 2]
]

def threeSum(nums: List[int]) -> List[List[int]]:
if not nums or len(nums) < 3:
return []
nums.sort()
n = len(nums)
res = []

if nums[0] > 0 or nums[-1] < 0:
return res

for i in range(n-2):
p1 = i + 1
p2 = n - 1

if i - 1 >= 0 and nums[i] == nums[i-1]:
continue
while p1 < p2:

if nums[p1] + nums[p2] + nums[i] < 0:
# while p1 < n-1 and nums[p1] == nums[p1+1]:
#     p1 += 1
p1 += 1
elif nums[p1] + nums[p2] + nums[i] > 0:
# while p2 > 0 and nums[p2] == nums[p2-1]:
#     p2 -= 1
p2 -= 1
elif nums[p1] + nums[p2] + nums[i] == 0:
res.append([nums[i], nums[p1], nums[p2]])
# print('done')
p1 += 1
p2 -= 1

return res

## 16. 最接近的三数之和

def threeSumClosest(nums: List[int], target: int) -> int:
if not nums or len(nums) < 3:
return

n = len(nums)
nums.sort()
res = []
nearest_sum = sum(nums[:3])
if nums[0] >= target:
return sum(nums[:3])

if nums[-1] <= target:
return sum(nums[-3:])

for i in range(n-2):
p1 = i + 1
p2 = n - 1

while p1 < p2:
temp = nums[i] + nums[p1] + nums[p2]
# print(temp)
if abs(temp - target) < abs(nearest_sum - target):
# res = [nums[i], nums[p1], nums[p2]]
nearest_sum = temp

if temp < target:
p1 += 1
elif temp > target:
p2 -= 1
else:
return target

return nearest_sum

## 18. 四数之和

[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
if not nums or len(nums) < 4:
return []

n = len(nums)

nums.sort()
res = []
for i in range(n-3):
# 保证nums[i]改变了
if i > 0 and nums[i] == nums[i-1]:
continue
for j in range(i+1, n-2):
# 保证nums[j]改变了
if j > i + 1 and nums[j] == nums[j-1]:
continue

h = j + 1
k = n - 1

while h < k:
four_sum = nums[i] + nums[j] + nums[h] + nums[k]

if four_sum > target:
k -= 1
elif four_sum < target:
h += 1

else:
res.append([nums[i], nums[j], nums[h], nums[k]])
while h < k and nums[h] == nums[h+1]:
h += 1

while h < k and nums[k] == nums[k-1]:
k -= 1
k -= 1
h += 1
return res

## 49. 字母异位词分组

[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]

def groupAnagrams(strs: List[str]) -> List[List[str]]:
if not strs:
return []
if len(strs) < 2:
return [strs]

# 判断两个词是否为异位词
def isAnagram(s1, s2):
if not s1 and not s2:
return True
if not s1 or not s2 or len(s1) != len(s2):
return False

return sorted(s1) == sorted(s2)

dicts = {}

for s in strs:

flag = False
for w in dicts.keys():
if isAnagram(s, w):
dicts[w].append(s)
flag = True
if not flag:
dicts[s] = [s]

return list(dicts.values())

def groupAnagrams(strs: List[str]) -> List[List[str]]:
if not strs:
return []

dicts = {}
# 异位词排序之后相同

for s in strs:
sorted_s = ''.join(sorted(s))
if sorted_s in dicts:
dicts[sorted_s].append(s)
eles:
dicts[sorted_s] = [s]

return list(dicts.values())

def groupAnagrams(strs: List[str]) -> List[List[str]]:
if not strs:
return []

#
from collections import defaultdict
dicts = collections.defaultdict(list)
for s in strs:

# 统计每个字符出现的个数
arr = [0] * 26
for c in s:
arr[ord(c) - ord('a')] += 1

# 异位词只是单词顺序发生改变, 每个单词的计数并未变化
dicts[tuple(arr)].append(s)

return list(dicts.values())

## 219. 存在重复元素 II

def containsNearbyDuplicate(nums: List[int], k: int) -> bool:
if not nums:
return False

dicts = {}
n = len(nums)
flag = False

for i in range(n):
if nums[i] in dicts:
if i - dicts[nums[i]] <= k:
# 只要存在就为真
return True

# 不管nums[i] 是否在字典中, 都需要更新右边界
dicts[nums[i]] = i
return False

## 220. 存在重复元素 III

0, 1, 3 位于同一个桶

4, 5 位于同一个桶

9 位于同一个桶

1. 一个桶中包含多个元素
2. 如果当前元素与相邻桶中的元素相差小于t

def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
if not nums:
return False

bucket = {}
n = len(nums)

bucket_size = t + 1
for i in range(n):
num = nums[i] // bucket_size

# 如果该桶不为空, 则直接返回True
# 每个桶只包含一个元素
if num in bucket:
return True

# 将元素放入桶中
bucket[num] = nums[i]

# 检查前一个桶
if num - 1 in bucket and abs(bucket[num - 1] - nums[i]) <= t:
return True

# 检查后一个桶
if num + 1 in bucket and abs(bucket[num + 1] - nums[i]) <= t:
return True

# 对索引进行了限制, 保证所有桶内的元素都处于 (i-k, i], 相当于一个固定大小的滑动窗口
if i >= k:
bucket.pop(nums[i-k] // bucket_size)

return False

## 447. 回旋镖的数量

[[0,0],[1,0],[2,0]]

2

def numberOfBoomerangs(points: List[List[int]]) -> int:
if not points or len(points) < 3:
return 0

n = len(points)

def dist(p1, p2):
return (p1[0] - p2[0]) * (p1[0] - p2[0])  + (p1[1] - p2[1]) * (p1[1] - p2[1])

res = 0
for i in range(n):
dicts = {}
for j in range(n):
if j == i:
continue

dis = dist(points[i], points[j])
dicts[dis] = dicts.get(dis, 0) + 1

for _, v in dicts.items():
if v > 1:
res += v * (v - 1)

return res

## 149. 直线上最多的点数

^
|
| o
| o
| o
+------------->
0 1 2 3 4

^
|
| o
| o o
| o
| o o
+------------------->
0 1 2 3 4 5 6

def maxPoints(points: List[List[int]]) -> int:
if not points:
return 0
if len(points) < 3:
return len(points)

n = len(points)
def slope(p1, p2):
if p1[0] == p2[0]:
return float('inf')

return (p1[1] - p2[1]) / (p1[0] - p2[0])

from  collections import Counter

for p in points:
repeated_cnt = sum([1 for point in points if point == p])

counter = Counter([slope(p, point) for point in points if point != p])

temp = counter.most_common(1)[0][1] + repeated_cnt

res = max(res, temp + repeated_cnt)

return res


## 454. 四数相加 II

A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]

2

1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int:
if not A:
return 0

dicts = {}

for a in A:
for b in B:
# 使用字典保存a + b, 对两数之和进行计数
dicts[a+b] = dicts.get(a+b, 0) + 1

res = 0
for c in C:
for d in D:
if -(c + d) in dicts:
res += dicts[-(c + d)]
return res


82 声望
12 粉丝
0 条评论