LeetCode 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
输入: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
思路
- 暴力法:超时
- 方法二:
- 定义一个字典sums,存放数组a,b各个元素的和以及出现次数;定义count用于累加四数相加为0的个数
- 遍历数组c,d求各个元素的和,每求得一个和就计算该数的相反数,并在sums里查找。若sums里存在该数,说明满足四数相加等于0,count应加上sums中该数出现的次数
代码
class Solution(object):
def fourSumCount(self, nums1, nums2, nums3, nums4):
"""
:type nums1: List[int]
:type nums2: List[int]
:type nums3: List[int]
:type nums4: List[int]
:rtype: int
"""
count = 0
sums = dict() # key: sum, value: count 存放数组a,b的各个元素的和
for i in range(len(nums1)):
for j in range(len(nums2)):
sum = nums1[i] + nums2[j]
if sum in sums:
sums[sum] += 1
else:
sums[sum] = 1
for i in range(len(nums3)):
for j in range(len(nums4)):
sum = nums3[i] + nums4[j]
if 0-sum in sums:
count += sums[0-sum]
return count
LeetCode 383 赎金信
题目描述:
给你两个字符串:
ransomNote
和magazine
,判断ransomNote
能不能由magazine
里面的字符构成。如果可以,返回true
;否则返回false
。
magazine
中的每个字符只能在ransomNote
中使用一次。输入:ransomNote = "a", magazine = "b" 输出:false
思路
- 定义一个长为26的数组count,用于存放
magazine
各个字母的数量 - 遍历
magazine
,每个字母在count对应的位置+1 - 遍历
ransomNote
,每个字母在count对应的位置-1。每次-1后判断一次,若-1后count上的数值<0,说明magazine
上对应的字母已不够
代码
class Solution(object):
def canConstruct(self, ransomNote, magazine):
"""
:type ransomNote: str
:type magazine: str
:rtype: bool
"""
count = [0 for _ in range(26)]
for i in range(len(magazine)):
count[ord(magazine[i]) - ord('a')] += 1
for i in range(len(ransomNote)):
count[ord(ransomNote[i]) - ord('a')] -= 1
if count[ord(ransomNote[i]) - ord('a')] < 0:
return False
return True
if __name__ == "__main__":
ransomNote = "chess"
magazine = "speechless"
solution = Solution()
print(solution.canConstruct(ransomNote, magazine))
LeetCode 15 三数之和
题目描述:
给你一个整数数组
nums
,判断是否存在三元组[nums[i], nums[j], nums[k]]
满足i != j
、i != k
且j != k
,同时还满足nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为0
且不重复的三元组。**注意:**答案中不可以包含重复的三元组。
输入: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] 。输出的顺序和三元组的顺序并不重要。
思路及代码
-
暴力哈希法:超时
class Solution(object): def threeSum(self, nums): """ :type nums: List[int] :rtype: List[List[int]] """ nums.sort() res = [] for i in range(len(nums)): for j in range(i+1, len(nums)): if -(nums[i] + nums[j]) in nums[j+1:]: temp = [nums[i], nums[j], -(nums[i] + nums[j])] if temp not in res: res.append(temp) return res
-
双指针法:
- 对原数组进行从小到大排序
- i从左到右遍历数组
- 定义左指针 left=i+1,右指针 right=len(nums)-1,判断 [nums[i], nums[left], nums[right]] 的值
- 若小于0,则left右移(加大),反之right左移(减小),直到两个指针相遇
- 为避免重复,当nums[i] == nums[i-1] 时,可跳过
class Solution(object): def threeSum(self, nums): """ :type nums: List[int] :rtype: List[List[int]] """ nums.sort() print(nums) res = [] for i in range(len(nums)): left = i + 1 right = len(nums) - 1 if i == 0 or (i > 0 and nums[i] != nums[i-1]): while left < right: sum = nums[i] + nums[left] + nums[right] if sum == 0: res.append([nums[i], 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 #以上两个while是为了避免left和right与之前的重复 left += 1 right -= 1 elif sum < 0: left += 1 else: right -= 1 return res
LeetCode 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
你可以按 任意顺序 返回答案 。
输入:nums = [1,0,-1,0,-2,2], target = 0 输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
思路及代码
在上一题《三数之和》的基础上,在外围再加一层for循环,同时多了一层去重
class Solution(object):
def fourSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[List[int]]
"""
nums.sort()
res = []
for j in range(len(nums) - 3):
for i in range(j+1, len(nums) - 2):
left = i + 1
right = len(nums) - 1
if j == 0 or (j > 0 and nums[j] != nums[j-1]):
if i == j + 1 or (i > j + 1 and nums[i] != nums[i-1]):
while left < right:
sum = nums[j] + nums[i] + nums[left] + nums[right]
if sum == target:
res.append([nums[j], nums[i], 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 sum < target:
left += 1
else:
right -= 1
return res
总结
- 有时候使用哈希表可以减少一层for循环,提高算法效率
- 双指针法仍然发挥很大的作用,但也有很多种变形用法,需要多积累多记住