今日任务
-
454.四数相加II
-
383. 赎金信
-
15. 三数之和
-
18. 四数之和
-
总结
454.四数相加II
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
"""
hashmap = {}
result = 0
for a in nums1:
for b in nums2:
hashmap[a+b] = hashmap.get(a+b,0)+1
for c in nums3:
for d in nums4:
target = 0-(c+d)
if target in hashmap:
#不是直接在result上面加一,因为统计了这个和出现了多次了,所以应该返回map的value的值
result += hashmap.get(target)
return result
重点:
- 为什么会想到使用hashmap:
因为不用考虑会不会出现重复项。只需要将前面两个的和组合,然后相减,找map里面是否有存在,所以使用hashmap
- 用什么哈希表的类型:
不能用数组,-2的28次方 <= nums1[i], nums2[i], nums3[i], nums4[i] <= 2的28次方,太大了,用数组占的地方太大。
- map的内部设置:
这里很巧妙,key做两个数组的和,value统计次数。
题目链接/文章讲解/视频讲解:代码随想录
二刷:
未ac
三刷
var fourSumCount = function(nums1, nums2, nums3, nums4) {
let map = new Map()
let result = 0
for(let i = 0;i<nums1.length;i++){
for(let j = 0;j<nums2.length;j++){
let sum = nums1[i]+nums2[j]
map.set(sum, (map.get(sum) || 0) + 1)
}
}
console.log(map)
for(let num3 of nums3){
for(let num4 of nums4){
let sum = num3+num4
result += (map.get(0-sum) || 0)
}
}
return result
};
383. 赎金信
class Solution(object):
def canConstruct(self, ransomNote, magazine):
"""
:type ransomNote: str
:type magazine: str
:rtype: bool
"""
hashmap = 26*[0]
for letter in magazine:
hashmap[ord(letter) - ord("a")] += 1
for letter in ransomNote:
hashmap[ord(letter) - ord("a")] -= 1
#如何小于0的,返回false
for i in hashmap:
if i < 0:
return False
#循环完毕,如果没有就返回True
return True
题解好像跟我有点出入,可能是我理解的题目意思错误。
应该是random的所有东西都出现在magazine里头,没出现就是false
class Solution(object):
def canConstruct(self, ransomNote, magazine):
"""
:type ransomNote: str
:type magazine: str
:rtype: bool
"""
hashmap = 26*[0]
for letter in magazine:
hashmap[ord(letter) - ord("a")] += 1
for letter in ransomNote:
if hashmap[ord(letter) - ord("a")] == 0:
return False
else:
hashmap[ord(letter) - ord("a")] -= 1
return True
题目链接/文章讲解:代码随想录
二刷:
ac了
三刷:ac
var canConstruct = function(ransomNote, magazine) {
let arr = new Array(26).fill(0)
for(let i = 0;i<ransomNote.length;i++){
arr[ransomNote[i].charCodeAt()-'a'.charCodeAt()] +=1
}
for(let i = 0;i<magazine.length;i++){
arr[magazine[i].charCodeAt()-'a'.charCodeAt()] -= 1
}
for(let a of arr){
if(a > 0){
return false
}
}
return true
};
15. 三数之和
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
#先用hashmap写一下
result = []
hashmap = {}
for i in range(len(nums)):
hashmap[nums[i]] = i
for l in range(len(nums)):
for r in range(l+1,len(nums)):
target = 0 - (nums[l]+nums[r])
if target in hashmap and hashmap[target] != r and hashmap[target] != l:
temp = [nums[l],nums[r],target]
temp.sort()
result.append(temp)
return set(list(result))
使用hashmap也算解决了一半,但是.......好多重复值,去不掉
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = []
nums.sort()
for i in range(len(nums)):
left = i+1
right = len(nums)-1
#如果第一个数大于0,直接返回,后面都是更大的
if nums[i] > 0:
break
if i >= 1 and nums[i] == nums[i-1]:
continue
#一直在left 和right区间中寻找有无等于0
while left < right:
summ = nums[i] + nums[left] + nums[right]
if summ < 0:
left += 1
elif summ > 0:
right -= 1
else:
result.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
left += 1
right -= 1
return result
写错的地方:
if nums[i] > 0:
break
if i >= 1 and nums[i] == nums[i-1]:
continue
这里放在while循环里面判断了,应该在一开始就判断一下nums[i]是不是大于0,不是直接跳出循环。这个break,我写成return 了,所以返回没有结果,这里要注意
else:
result.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
left += 1
right -= 1
这里后面的while循环,写成了nums【left-1】 == nums【left】,导致out of index
while left != right:也可以写成left < right
忘记加上: left += 1
right -= 1 导致出错
重点:
- 如何去重
- i 的去重
如果i 和前面相同,就去重。为什么不跟后面比较,因为占领了left的位置,left也要去重的。重复操作了,而且是3sum
- left,right的去重
位置是sum=0的时候操作,而且是比较后面的元素,如果重复就continue一下
- 如何使用双指针,怎么操作?
使用i(for),再使用left(left = i + 1)和right指针。。。
题目链接/文章讲解/视频讲解:代码随想录
使用双指针的算法
三刷:
var threeSum = function(nums) {
let result = []
nums.sort((a,b)=>a-b)
// 双指针算法
for(let i = 0;i<nums.length;i++){
if(nums[i]>0) return result
if(i>0 &&nums[i] === nums[i-1]) continue
let left = i+1
let right = nums.length -1
while(left<right){
let threeSum = nums[i]+nums[right]+nums[left]
let f = nums[i]
let s = nums[left]
let t = nums[right]
if(threeSum === 0){
result.push([f,s,t])
while(left < right && nums[left] === nums[left+1]){
left ++
}
while(left < right&& nums[right] === nums[right-1]){
right--
}
left += 1
right -= 1
}else if(threeSum<0){
left += 1
}else{
right -= 1
}
}
}
console.log(result)
return result
};
18. 四数之和
class Solution(object):
def fourSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[List[int]]
"""
result = []
nums.sort()
for i in range(len(nums)):
#剪枝,如果是负数,他就直接break了
if target > 0 and nums[i] > target and nums[i] > 0:
break
#去重
if i > 0 and (nums[i] == nums[i-1]):
continue
for j in range(i+1,len(nums)):
#剪枝
if target > 0 and nums[i]+nums[j] > target and nums[j] > 0:
break
#因为要间隔一下,不然的话比较的是i = j嘛
if j>i+1 and nums[j] == nums[j-1]:
continue
left = j + 1
right = len(nums)-1
while left < right:
summ = nums[i] + nums[j] +nums[left] + nums[right]
if summ == target:
result.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
right -= 1
left += 1
elif summ > target:
right -= 1
else:
left += 1
return result
与上面一题最大的区别就是多了剪枝环节
题目链接/文章讲解/视频讲解:代码随想录
二刷:
未ac
剪枝操作是因为,我们需要考虑到数组万一都是负数。【-4,-1,0,0】 target = -5,这时候,符合情况的,如果单考虑nums[0] > target,,就会错过结果集。
三刷
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var fourSum = function(nums, target) {
let result = []
nums.sort((a,b)=>a-b)
for(let i = 0;i<nums.length;i++){
// 一级剪枝
if(target > 0 && nums[i]>0 && nums[i]>target) break
// 一级去重
if(i>0 && nums[i]===nums[i-1]) continue
for(let j = i+1;j<nums.length;j++){
// 二级剪枝
if(target > 0 && nums[i]+nums[j] > 0 && nums[i]+nums[j] > target) break
// 二级去重
if(j-1>i && nums[j] === nums[j-1]) continue
let left = j +1
let right = nums.length-1
while(left < right){
let threeSum = nums[i]+nums[j]+nums[right]+nums[left]
if(threeSum === target){
result.push([nums[i],nums[j],nums[right],nums[left]])
while(left < right && nums[left] === nums[left + 1]){
left +=1
}
while(left < right && nums[right] === nums[right-1]){
right -= 1
}
left += 1
right-=1
}
else if(threeSum > target){
right -= 1
}else{
left += 1
}
}
}
}
return result
};