LeetCode454.四数相加Ⅱ
题目链接:454. 四数相加 II
使用哈希表,首先将前两个数组的和存储到哈希表中,后续检查0减去后两个数组的和是否在哈希表中
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
count = 0
twoListSum = collections.defaultdict(int)
for a in nums1:
for b in nums2:
twoListSum[a + b] += 1
for c in nums3:
for d in nums4:
if twoListSum[0 - c - d] is not 0:
count += twoListSum[0 - c - d]
return count
LeetCode383.赎金信
题目链接:383. 赎金信
简单hash即可
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
record = [0] * 26
for char in magazine:
record[ord(char) - ord('a')] += 1
for char in ransomNote:
if not record[ord(char) - ord('a')]:
return False
record[ord(char) - ord('a')] -= 1
return True
LeetCode15.三数之和
题目链接:15. 三数之和
双指针法:
双指针的一般思路:利用数组的有序性,达到搜索所有解「剪枝」的目的。首先对输入数组排序,循环变量为i
,设置变量left
和right
分别位于i
后面的区间[i + 1, len - 1]
的头和尾。
-
枚举起点
i
,在[i + 1, len - 1]
区间里查找两数之和为0-nums[i]
,这里记target =0 -nums[i]
。 -
如果
nums[left] + nums[right] > target
,说明两个数的和太大了,由于数组已经有序,nums[left + 1] + nums[right] > target、nums[left + 2] + nums[right] > target
一定成立,但是nums[left] + nums[right - 1]
与target
的大小关系我们还不知道,此时需要考虑将right
左移,即right--
; -
如果
nums[left] + nums[right] < target
,说明两个数的和太小了,由于数组已经有序,nums[left] + nums[right - 1] < target、nums[left] + nums[right - 2] < target
一定成立,但是nums[left + 1] + nums[right]
与target
的大小关系我们还不知道,此时需要考虑将left
右移,即left++
; -
如果
nums[left] + nums[right] == target
,说明得到了一组可行解。此时left
和right
同时向中间移动一格; -
如果
left
和right
移动以后的值和上一个一样,还必须继续移动,否则会将重复的结果输出到结果集中。这一步就是在做**「剪枝」**的工作。
另外,根据题意,我们还容易分析出两个剪枝的操作:
- 如果第 1个数大于 0 ,由于数组有序,后面的数都大于等于第 1 个数,三个数之和一定大于 0,直接退出整个逻辑,后面不可能再搜索出满足题意的结果;
- 在枚举第 1 个数的时候,如果下一轮的值与上一轮的值相等,这一轮搜索就可以跳过。理由也很简单,因为这一轮与上一轮相比,候选元素少了一个,可能的结果在上一轮一定已经搜索得到,如果继续搜索,一定会出现重复。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
n = len(nums)
res = []
for i in range(n):
left = i + 1
right = n - 1
# 剪枝2
if nums[i] > 0:
break
# 剪枝3
if i > 0 and nums[i] == nums[i-1]:
continue
while left < right:
total = nums[i] + nums[left] + nums[right]
if total is 0:
res.append([nums[i], nums[left], nums[right]])
# 剪枝1
while left < right and nums[left] == nums[left+1]:
left += 1
while left < right and nums[right] == nums[right-1]:
right -= 1
left += 1
right -= 1
elif total < 0:
left += 1
else:
right -= 1
return res
LeetCode18.四数之和
题目链接:18. 四数之和
这里注意辨析is
与==
的区别:参考 Python中is与==的使用区别详解
==
是比较两个对象的内容是否相等,即两个对象的“值“”是否相等,不管两者在内存中的引用地址是否一样- is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。即is比较两个条件:1.内容相同。2.内存中地址相同
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
n = len(nums)
res = []
for i in range(n):
if nums[i] > target > 0:
break
if i > 0 and nums[i] == nums[i-1]:
continue
for j in range(i + 1, n):
if nums[i] + nums[j] > target > 0:
break
if j > i+1 and nums[j] == nums[j - 1]:
continue
left = j + 1
right = n - 1
while left < right:
total = nums[i] + nums[j] + nums[left] + nums[right]
if total == target: # 这里一定要用==进行比较,不然会有 -11 != -11的尴尬现象
res.append([nums[i], nums[j], nums[left], nums[right]])
while left < right and nums[left] == nums[left + 1]:
left += 1
while left < right and nums[right] == nums[right - 1]:
right -= 1
left += 1
right -= 1
elif total < target:
left += 1
else:
right -= 1
return res