454.四数相加II
给你四个整数数组 nums1
、nums2
、nums3
和 nums4
,数组长度都是 n
,请你计算有多少个元组 (i, j, k, l)
能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
示例 1:
输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2] 输出:2 解释: 两个元组如下: 1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0 2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
示例 2:
输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0] 输出:1
本题求的是满足条件的元组的数量不需要去重,所以直接使用哈希表来做。因为只需要求出元组数不需要知道具体的索引,所以将4个数分为两组,两组的和为0则count加一,用一个哈希表(defaultdict)储存第一组的和,然后遍历第二组,使用dict.get(target,0)来在哈希表搜索key为第一组和的负数的数量(值)。
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
record = defaultdict(int)
for num1 in nums1:
for num2 in nums2:
record[num1+num2] += 1
count = 0
for num3 in nums3:
for num4 in nums4:
count += record.get(-(num3+num4),0)
return count
383. 赎金信
给你两个字符串:ransomNote
和 magazine
,判断 ransomNote
能不能由 magazine
里面的字符构成。
如果可以,返回 true
;否则返回 false
。
magazine
中的每个字符只能在 ransomNote
中使用一次。
示例 1:
输入:ransomNote = "a", magazine = "b" 输出:false
示例 2:
输入:ransomNote = "aa", magazine = "ab" 输出:false
示例 3:
输入:ransomNote = "aa", magazine = "aab" 输出:true
如果ransomNote
由 magazine
里面的字符构成,那么 magazine
字符肯定更多,所以用Counter()生成一个记录各字符频率的map,再遍历ransomNote,只需要判断ransomNote是否存在magazine里没有的字符,换言之map里不存在小于0的值,就可以得到结果
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
mag_count = Counter(magazine)
for ch in ransomNote:
mag_count[ch] -= 1
if mag_count[ch] < 0:
return False
return True
15. 三数之和
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请
你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
这道题也可以用哈希表做但是要去重,剪枝的逻辑非常复杂难以实现,所以使用双指针来完成。因为要使用双指针所以需要对数组先进行排序。用双指针可以求得两个数的和,再通过一个指针i遍历整个数组,来判断两个数的和与i相加是否等于target。为了避免重复,左指针从i的下一位开始。在考虑去重时,因为在循环i的每次迭代中都遍历了整个数组,所以当i等于上一次循环时,在上次循环时就已经考虑了所有情况,于是跳过这次循环。因为数组进行过排序,所以不存在(1,3,2)这样的组合,所以不用考虑(1,2,3)与(1,3,2)的重复,所以在考虑后两位的重复时只需要考虑与之前那位重复的情况,并且只需要在三元组符合条件时考虑。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
result = []
for i in range(len(nums)):
# 因为i在每次迭代中都遍历了整个列表,所以当i出现重复时
# 在前一次的遍历的时候已经考虑过所有情况了
if i>0 and nums[i] == nums[i-1]:
continue
left = i+1
right = len(nums)-1
while left < right:
if nums[i]+nums[left]+nums[right] > 0:
right -= 1
elif nums[i]+nums[left]+nums[right] < 0:
left += 1
else:
result.append([nums[i],nums[left],nums[right]])
left += 1
right -= 1
while nums[right] == nums[right+1] and left < right:
right -= 1
while nums[left] == nums[left-1] and left < right:
left += 1
return result
18. 四数之和
给你一个由 n
个整数组成的数组 nums
,和一个目标值 target
。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]]
(若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a
、b
、c
和d
互不相同nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0 输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
示例 2:
输入:nums = [2,2,2,2,2], target = 8 输出:[[2,2,2,2]]
这道题与上题要求类似,区别在于多了一个数,所以逻辑也相似,只不过循环两次。在去重时也通过不同的指针类型来写判断。
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
result = []
nums.sort()
for i in range(len(nums)):
if i > 0 and nums[i] == nums[i-1]:
continue
for j in range(i+1,len(nums)):
if j > i+1 and nums[j] == nums[j-1]:
continue
left = j+1
right = len(nums)-1
while left < right:
sum_ = nums[i]+nums[j]+nums[left]+nums[right]
if sum_ > target:
right -= 1
elif sum_ < target:
left += 1
else:
result.append([nums[i],nums[j],nums[left],nums[right]])
left += 1
right -= 1
while left<right and nums[left]==nums[left-1]:
left += 1
while left<right and nums[right]==nums[right+1]:
right -= 1
return result
多数之和怎么判断用指针法还是哈希法?
这种题目都可以用哈希法硬解,指针法更适用的原因是题目要求给出具体的元组而非有多少个元组符合条件,并且明确提示不包含重复元组,因此需要去重没法用简单的哈希法完成。