代码随想录算法训练营第七天|leetcode454.四数相加II、leetcode383. 赎金信 、leetcode15. 三数之和、leetcode18.四数之和
1 leetcode454.四数相加II
题目链接:454. 四数相加 II - 力扣(LeetCode)
文章链接:代码随想录
视频链接:学透哈希表,map使用有技巧!LeetCode:454.四数相加II_哔哩哔哩_bilibili
自己的思路:第一反应就是暴力搜索,一层一层for循环来完成,就是会超时
1.1 自己的代码
纯纯暴力搜索
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
count = 0
for i in nums1:
for j in nums2:
for k in nums3:
for l in nums4:
if i+j+k+l == 0:
count +=1
return count
1.2 哈希表的方法
1.2.1哈希表未调用函数
之前出错的一个地方,如果查询的键未在函数内部,则需要建立一个键以及所对应的值
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
hashmap = dict()
count = 0
for i in nums1:
for j in nums2:
if i+j in hashmap:
hashmap[i+j] +=1
else :
hashmap[i+j] = 1
for k in nums3:
for l in nums4:
num = 0-(k+l)
if num in hashmap:
count += hashmap[num]
return count
1.2.2 使用get函数
之前会,但是没用过,今儿深切感受到了,其使用方法就是在字典内部看看对应的键的位置,没有就是获得一个键和值,值为0
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
hashmap = dict()
count = 0
for i in nums1:
for j in nums2:
hashmap[i+j] = hashmap.get(i+j,0)+1
for k in nums3:
for l in nums4:
num = 0-(k+l)
if num in hashmap:
count += hashmap[num]
return count
1.3 本题小结
- 这道题很巧妙的地方就是如何求值,先将两个数组的值进行存储在一个字典中,然后用目标值减去另外两个数组的值得到一个值,然后这个值在字典中查找,这样时间复杂度只有n的平方了
- 在一个空字典中加键值对的方法,一种就是直接判断,不在里面就直接
num[key] = 1
或者就是num[key] = num.get(key,0)+1
2 leetcode 383. 赎金信
文章链接:代码随想录
自己的思路:
- 字符串总共有26个,所以建立一个可以容纳26个字符串的哈希表,初始值为0
- 统计第一个字符串
s
中每个字母出现的次数,这里计算就是用字符串位置减去第一个字母即'a'
的值,计算两个字符串的值在python中转化为对ASCII码计算,函数是ord()
,然后就是统计每个字符串出现的次数,对其数值进行相加 - 对第二个字符串
t
中的数据对哈希表进行一个减法的操作 - 对字符串中的字符进行循环,如果哈希表的值有小于
0
的,则证明两个字符串不相等,否则就是相等
2.1 自己的代码
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
recorde = [0]*26
for i in magazine:
recorde[ord(i)-ord('a')] +=1
for j in ransomNote:
recorde[ord(j)-ord('a')] -=1
for k in range(26):
if recorde[k] < 0:
return False
return True
2.2 哈希表的方法
看了别人的方法,觉得这道题的代码可以简单一点
2.2.1 数组的方法
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
recorde = [0]*26
for i in magazine:
recorde[ord(i)-ord('a')] +=1
for j in ransomNote:
recorde[ord(j)-ord('a')] -=1
if recorde[ord(j)-ord('a')] < 0:
return False
return True
2.2.2 字典的方法
字典的方法也是在随想录里面学习到的,发现这个方法真的很巧妙,就是如果目标键不在我们的字典中或者在字典中值为0,就代表没有
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
recorde = dict()
for i in magazine:
recorde[i] = recorde.get(i,0)+1
for j in ransomNote:
if j not in recorde or recorde[j] == 0:
return False
recorde[j] -=1
return True
2.3 本题小结
- 这道题的基本思想和第一个哈希表的方法很相似,而且做法几乎一样
- 使用字典的时候,一定要注意键值对的值小于0会报错
3 leetcode15. 三数之和
文章链接:代码随想录
视频链接:梦破碎的地方!| LeetCode:15.三数之和_哔哩哔哩_bilibili
自己的思路:原计划是使用字典来存储,然后算一个值出来,如果这个值在字典里面并且和循环中的值不同,则进行输出,发现做的时候会有重复的
3.1视频后的思路
使用双指针的方法,就是不断去判断,感觉双指针的思路时间就比较久,但是结果还算比较好的,就是要去判断有没有相同的数,如果出现了就要往后面移动一位,这个点没想通开始的时候
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
result = []
nums.sort()
for i in range(len(nums)):
if nums[i]>0:
return result
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]])
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
3.2本题小结
- 感觉这道题难点就在于去重,还有就是判断有0以后,后面的while语句要有两个条件,分开写也不是不行,就是时间会变长
- 主要就是需要去重,返回的是值而不是下标,下标重复无所谓,但是不能让值重复
4 leetcode18.四数之和
文章链接:代码随想录
视频链接:难在去重和剪枝!| LeetCode:18. 四数之和_哔哩哔哩_bilibili
自己的思路:这道题才开始真的没思路,因为今天感觉自己很烦躁,一直做不好题,看了里面的讲解以后,说再嵌套一层循环即可
4.1 双指针的思路
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
result = []
for i in range(len(nums)):
if nums[i]>target and nums[i]>=0:
break
if i>0 and nums[i]==nums[i-1]:
continue
for k in range(i+1,len(nums)):
if nums[i]+nums[k]>target and nums[i]+nums[k]>=0:
break
if k>i+1 and nums[k] == nums[k-1]:
continue
left = k+1
right = len(nums)-1
while left<right:
sum_ = nums[i]+nums[k]+nums[left]+nums[right]
if sum_<target:
left +=1
elif sum_>target:
right -=1
else:
result.append([nums[i],nums[k],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
4.2 本题小结
- 其实这道题真的和三数之和超级超级像,感觉没有任何区别
- 就是有一个去重的操作,必须
nums>=target
的时候,还有就是target>0
,因为如果小于0也会出现问题
5 本章小结
- 其实这个地方很重要的一点,就是不能陷入整个哈希表里面,因为题目是多源的,就是只要能做就好,不要陷入进去
- 在空字典里面添加键值对的方法,就是
nums[a]=nums.get(a,0)