文章目录
前言
链接都不放了,放一个总的吧以后 代码随想录文章
454.四数相加II
思路
总体思路:昨天有两数相加的方法,所以这里4个划分为两个为一组遍历,转换为两数相加的方法
注意事项:本题比下面第四题简单,因为重复的也算,所以A、B数组如果有k个组合加起来都为3,C、D数组一种组合为-3,那么对应这个C、D组合的个数就有k个,就得算;
结构选择:因为不仅仅要存储A、B是否有过这个数,还要存储A、B之和出现这个数的次数,采用map结构
方法一 常规python
我写的代码:知道思路之后很简单,没有上面要注意的
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
map_ = {}
for a in nums1:
for b in nums2:
sum1 = a+b
if sum1 in map_:
map_[sum1] += 1
else:
map_[sum1] = 1
for c in nums3:
for d in nums4:
target = -c-d
if target in map_:
count += map_[target]
return count
使用字典的get属性:dict1.get(key, defatult)返回key对应的值,如果没有返回defatult的值
class Solution(object):
def fourSumCount(self, nums1, nums2, nums3, nums4):
# 使用字典存储nums1和nums2中的元素及其和
hashmap = dict()
for n1 in nums1:
for n2 in nums2:
hashmap[n1+n2] = hashmap.get(n1+n2, 0) + 1#注意这一句的写法
# 如果 -(n1+n2) 存在于nums3和nums4, 存入结果
count = 0
for n3 in nums3:
for n4 in nums4:
key = - n3 - n4
if key in hashmap:
count += hashmap[key]
return count
方法二 使用defaultdict
使用defaultdict就和c++的map差不多的使用方法了
from collections import defaultdict
class Solution:
def fourSumCount(self, nums1: list, nums2: list, nums3: list, nums4: list) -> int:
rec, cnt = defaultdict(lambda : 0), 0
for i in nums1:
for j in nums2:
rec[i+j] += 1
for i in nums3:
for j in nums4:
cnt += rec.get(-(i+j), 0)
return cnt
383. 赎金信
思路
时间复杂度: O(n)
空间复杂度: O(1)
方法一: 哈希表
和前面一天的有效字母异位词一样的思路
自己直接写的长这样,很简单
class Solution(object):
def canConstruct(self, ransomNote, magazine):
"""
:type ransomNote: str
:type magazine: str
:rtype: bool
"""
hash_ = [0]*26
#magazine code into hash table
for i in magazine:
hash_[ord(i)-ord('a')] += 1
for i in ransomNote:
hash_[ord(i)-ord('a')] -= 1
for ele in hash_:
if ele < 0:
return False
return True
使用defaultdict,思路和我一样
from collections import defaultdict
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
hashmap = defaultdict(int)
for x in magazine:
hashmap[x] += 1
for x in ransomNote:
value = hashmap.get(x)
if not value or not value:
return False
else:
hashmap[x] -= 1
return True
方法二 使用count
使用count:保证每个ransomNote中的字母个数小于杂志上的字母个数,擅于使用count属性;
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
for char in ransomNote:
if char in magazine and ransomNote.count(char) <= magazine.count(char):
continue
else:
return False
return True
15. 三数之和
这道题目很不简单;
题目分析:
- 主要是去重;例如如果数组长成[-1,-1,0,0,0,1,1,1,1]的样子,可能会得到好几次[-1,0,1]的结果;所以需要去重
- 本题目中返回元素元组而不需要下标,所以可以先排序
方法一 双指针法
其实这道题目使用哈希法并不十分合适,因为在去重的操作中有很多细节需要注意,在面试中很难直接写出没有bug的代码。
总体思路:a从头遍历【下标为i】,后面两个b和c之和必须为-a;再用双指针法找满足条件的b和c
双指针法核心:b和c分别用left和right指针,和-a比较,大了就left后移动,小了就right前移动
具体步骤:
- 首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时定一个下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。
- 移动left 和right呢, 如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到left与right相遇为止。
- 小细节:如果排序之后第一个数值已经大于0了就return,一定不满足
时间复杂度: O(n^2)
空间复杂度: O(1)
🎄去重注意点: a, b ,c, 对应的就是 nums[i],nums[left],nums[right],三个部分都需要去重,分为a的去重与b&c的去重
- 遍历的i需要和i-1比较,如果开头的a出现过了,就不要了;记住是当i>0的时候,从第二个元素开始
- 后面的b+c也会重:例如[-1,0,0,0,1,1,1]
b&c的去重方法:判断如果b和b+1相等,left就向中间移动,c和c-1相等,right就往中间移动;
明显需要注意:收获结果必须要放在去重的上面,否则出现[0,0,0,0]还没有记录结果呢,就没了
记一下carl的板书
自己写代码犯错
- list的sort只需要a.sort()就行了,它返回的是None,不要用a=a.sort()
- 如果第一个元素已经大于0,不需要进一步检查;后面的都不需要哦,直接return就行
- 去重b&c的时候:加上条件right > left;否则可能index会超出范围;并且必须使用while不能是if,否则b&c重复的就会去除不干净;
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
#排序,默认从小到大
nums.sort()
result = []
for i in range(len(nums)-1):#-1要不要都行
if nums[i] > 0:#如果a,b,c中第一个元素【最小】大于0的话,一定没有满足条件的
return result
if i >0 and nums[i] == nums[i-1]:#去除a和之前重合的情况
continue
left = i+1
right = len(nums)-1
#下面开始找left和right
while left < right:
sum_ = nums[i] + nums[left]+nums[right]
if sum_ > 0:
right -= 1
elif sum_ < 0:
left += 1
else:
result.append([nums[i],nums[left],nums[right]])
#去重b和c
while right > left and nums[right] == nums[right - 1]:
right -= 1
while right > left and nums[left] == nums[left + 1]:
left += 1
right -= 1
left += 1
return result
力扣网站耗尽了我今天所有的好脾气和耐心,一摸一样的代码,就是报错。
方法二 哈希法
我没看,有很多去重的小细节。力扣的网页bug浪费了今天太多时间了🌿
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
result = []
nums.sort()
# 找出a + b + c = 0
# a = nums[i], b = nums[j], c = -(a + b)
for i in range(len(nums)):
# 排序之后如果第一个元素已经大于零,那么不可能凑成三元组
if nums[i] > 0:
break
if i > 0 and nums[i] == nums[i - 1]: #三元组元素a去重
continue
d = {}
for j in range(i + 1, len(nums)):
if j > i + 2 and nums[j] == nums[j-1] == nums[j-2]: # 三元组元素b去重
continue
c = 0 - (nums[i] + nums[j])
if c in d:
result.append([nums[i], nums[j], c])
d.pop(c) # 三元组元素c去重
else:
d[nums[j]] = j
return result
18. 四数之和
思路
总体思路:和三数之和思路一致,就是在外面又套了一层循环for k来处理多出来的元素
细节处理:去重和剪枝
- 一级剪枝:for k,在这里不能因为nums[k]>target就break了,因为有可能出现下面的情况nums=[-4,-1,0,0] target = -5; 如果是负数,两个负数相加会变小;所以for k 的剪枝要变成nums[i] > target && (nums[i] >=0 || target >= 0)
- 一级去重:如果**k>0**,并且和k-1对应元素值相同,那么需要continue
- 二级剪枝:i=k+1,思路和一级剪枝一样,就是要把nums[k]+nums[i]看成一个整体进行判断;
- 二级去重:如果**i>k+1**【背住这个;理解:因为k固定之后,出现两个一样的i才需要往后面移动】,并且和i-1元素相同,continue;
注意:二级剪枝的时候只能用break,退出这个i循环,k继续
class Solution(object):
def fourSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[List[int]]
"""
result = []
nums.sort()
for k in range(len(nums)):
if nums[k]>target and nums[k]>0 :
return result #一级剪枝
if k>0 and nums[k] == nums[k-1]:#一级去重
continue
for i in range(k+1,len(nums)):
if nums[k]+nums[i]>target and target > 0:#2级剪枝
# return result
break
if i > k+1 and nums[i] == nums[i-1]:
continue
left = i+1
right = len(nums)-1
while left < right:
sum_ = nums[k]+nums[i] +nums[left]+nums[right]
if sum_ > target:
right -= 1
elif sum_ < target:
left += 1
else:
result.append([nums[k],nums[i],nums[left],nums[right]])
#去重b和c
while right > left and nums[right] == nums[right - 1]:
right -= 1
while right > left and nums[left] == nums[left + 1]:
left += 1
right -= 1
left += 1
return result
总结
没有时间慢慢调代码,时间真的很紧张;每天最多只能花3h;