LeetCode 454.四数相加Ⅱ:
看到题目后的思路:
可以算作之前两数之和的扩展。具体思路是,
① 首先遍历其中两个数组A和B,将两个元素的和与和出现的次数计入哈希表中,其中key为元素和,value为次数。
② 遍历剩下两个数组C和D,判断0-C[i]-D[j]是否在哈希表中,在的话当前的计数count + value。
③ 因为题目中给出的是四个数组,在四个数组中各找一个元素满足条件,因此不需要去除重复的元素(比如A[i] + B[j] = 1 + 2 , A[k] + B[l] = 2 + 1)
# 使用dict字典和dict.get
# dict.get(key, value)根据key获取对应的值,不存在则返回默认值value
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 = dict()
# 创建哈希表
for num1 in nums1:
for num2 in nums2:
hashmap[num1 + num2] = hashmap.get(num1+num2, 0) + 1
count = 0 # 计数
for num3 in nums3:
for num4 in nums4:
value = hashmap.get(0 - num3 - num4, 0)
count += value
return count
LeetCode 383.赎金信:
看到题目后的思路:
- 哈希表
是字母异构体的拓展,并且字符串也只使用小写字母,思路相似:
① 使用数组构造magazine的哈希表,下标对应字母,值为字母出现的次数
② 遍历randomNote,哈希表中每个字母对应的位置的值 - 1
③ 如果最后哈希表中出现负数,表明randomNote不能由magazine里面的字符构成
class Solution(object):
def canConstruct(self, ransomNote, magazine):
"""
:type ransomNote: str
:type magazine: str
:rtype: bool
"""
record = [0] * 26
for s in magazine:
record[ord(s) - ord('a')] += 1
for r in ransomNote:
record[ord(r) - ord('a')] -= 1
for r in record:
if r < 0:
return False
return True
- 暴力
双重循环遍历ran和maga,当m在ran中出现时,ran中移除对应的元素
ran = list(ransomNote)
maga = list(magazine)
# 暴力
for m in maga:
for r in ran:
if m == r:
ran.remove(r)
break
if len(ran) == 0:
return True
return False
LeetCode 15.三数之和 :
看到题目后的思路:
- 双指针
因为题目需要返回的是数值而不是下标,所以可以采用先排序数组再使用双指针的方法实现
① 本题中双指针的主要思路是,首先使用 i 遍历数组中的元素,双指针left = i + 1,right = len(num) - 1;若[left] + [right] <(>) 0 - [i],left向后移(right向前移);若[left] + [right] == 0 - [i],将该三元组加入答案中
② 题目需要返回的是不重复的三元组,所以我们需要做去重的工作。这个工作可以分为两部分:对 i 的去重和对双指针的去重。
对 i 的去重:
[i] == [i - 1] continue
不能采用 [i] == [i + 1] continue,因为对于[0,0,0]输入数组来说,应当返回的三元组就是[0,0,0],如果采用[i] == [i + 1],最终返回NULL(因为 left 是从i + 1开始的)
③ 对双指针的去重:先找到符合条件的三元组,left和right再进行去重
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = []
nums.sort()
len_num = len(nums)
for i in range(len_num):
if nums[i] > 0: # 第一个元素大于0,后面一定不存在符合条件的三元组
break
if i > 0 and nums[i] == nums[i - 1]: # 对i的去重
continue
left, right = i + 1, len_num - 1
while left < right:
cursum = nums[i] + nums[left] + nums[right]
if cursum < 0:
left += 1
elif cursum > 0:
right -= 1
else:
result.append([nums[i], nums[left], nums[right]])
# 跳过相同的元素避免重复
while left < right and nums[right] == nums[right - 1]:
right -= 1
while left < right and nums[left] == nums[left + 1]:
left += 1
# 退出循环时,[right] = [right + 1], [left] = [left - 1]
right -= 1
left += 1
return result
- 哈希
思想与之前的求两个元素的和使用哈希表的思想相似,但是这里是先确定一个元素,在剩下的元素中使用哈希表求符合条件的元组。
去重比较复杂
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = []
nums.sort()
len_nums = len(nums)
for i in range(len_nums):
if nums[i] > 0: # 第一个元素大于0,后面不可能有符合条件的三元组
break
if i > 0 and nums[i] == nums[i - 1]: # 跳过重复的元素
continue
#print('i' + str(i) + ': ' + str(nums[i]))
hash_dict = {}
# 哈希表法
for j in range(i + 1, len_nums):
# 对于类似[0,0,0,0]的情况
if j > i + 2 and nums[j] == nums[j - 1] == nums[j - 2]:
continue
c = 0 - nums[i] - nums[j]
#print('j' + str(j) + ': ' + str(nums[j]))
#print('hash_dict')
#self.print_list(hash_dict)
if c in hash_dict:
result.append([nums[i], nums[j], c])
# 对于类似[-2,0,0,2,2]的情况
hash_dict.pop(c)
else:
hash_dict[nums[j]] = j
return result
def print_list(self, plist):
for key in plist:
print(key)
print('\n')
实现过程中遇到的困难:
使用哈希表的去重比较复杂,基本是遇到错误,将错误实例的情况加上去。
LeetCode 18.四数之和:
看到题目后的想法:
思路与三数之和相同,只是从一重循环确定第一个元素变为了二重循环确定第二个元素。重点在于剪枝
① 需要注意的是target是题目给定的,可能>0,可能<0,而排序后的数组按照从大到小排列,因此剪枝只能在target > 0的时候进行剪枝。
②确定第一个元素剪枝的部分是target > 0并且当前元素 > target。第二个元素剪枝的部分是target > 0并且当前两个元素的和 > target
class Solution(object):
def fourSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[List[int]]
"""
result = []
nums.sort()
len_nums = len(nums)
for i in range(len_nums):
# 第一个元素a去重
if i > 0 and nums[i] == nums[i - 1]:
continue
# 剪枝。target > 0时可以剪枝
if nums[i] > target and target > 0:
break
#print('i: ' + str(i) + ' ' + str(nums[i]))
for j in range(i + 1, len_nums):
# 第二个元素b去重
if j > i + 1 and nums[j] == nums[j - 1]:
continue
#print('j: ' + str(j) + ' ' + str(nums[j]))
# target > 0时如果前两个元素的和超过target,后面一定不存在满足条件的四元组
if nums[i] + nums[j] > target and target > 0:
break
left, right = j + 1, len_nums - 1
while left < right:
cursum = nums[i] + nums[j] + nums[left] + nums[right]
if cursum < target:
left += 1
elif cursum > target:
right -= 1
else:
#print('left: ' + str(left) + ' ' + str(nums[left]))
#print('right: ' + str(right) + ' ' + str(nums[right]))
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
left += 1
right -= 1
return result
实现过程中遇到的困难:
剪枝,最开始没有注意到target 可以小于0,所以按照三数之和进行求解。
学习收获:
加深了对哈希表的使用
学会了python中的dict.get方法
剪枝和去重