454.四数相加II
文档讲解:代码随想录
暴力法会超出时间限制,时间复杂度是
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
count = 0
for i in range(len(nums1)):
for j in range(len(nums2)):
for k in range(len(nums3)):
for n in range(len(nums4)):
if(nums1[i]+nums2[j]+nums3[k]+nums4[n]) == 0:
count +=1
return count
这道题目是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况
用数组来保存结果,还是会超出时间限制,原因是最后判断两两数组的和的时候会有重复判断的情况,count一直是以1为单位进行判断的
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
#分解问题,四个数相加分解为两个数相加,先算出来两个数组的和有哪些情况,再进行组合
sum1=[]
sum2=[]
count = 0
for i in range(len(nums1)):
for j in range(len(nums2)):
sum1.append(nums1[i]+nums2[j])
for i in range(len(nums3)):
for j in range(len(nums4)):
sum2.append(nums3[i]+nums4[j])
for i in sum1:
# if -i in sum2: #不可以这样写,因为-i在sum2中可能有很多个,这样只是加了一个
# count +=1
for j in sum2:
if j == -i:
count=count+1
return count
改进:用字典来保存和与次数,相同的数判断一次就可以,count会增加很多,而不是1
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
sum1={}
sum2={}
count = 0
for i in nums1:
for j in nums2:
sum1[i+j] = sum1.get((i+j),0) + 1 #注意这个写法,还挺常用的
for i in nums3:
for j in nums4:
sum2[i+j] = sum2.get((i+j),0) + 1
for i in sum1:
if -i in sum2:
count += sum1[i] * sum2[-i] #这里count增加的不再是1了
print(sum1)
return count
383. 赎金信
文档讲解:代码随想录
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
a = [0] * 26
for i in magazine:
a[ord(i) - ord('a')] +=1
for j in ransomNote:
a[ord(j) - ord('a')] -=1
##只要a中不出现负数,就证明magazine中的字母足以覆盖ransomNote中的字母
return all(x >= 0 for x in a)
第15题. 三数之和
文档讲解:代码随想录
说到去重,其实主要考虑三个数的去重。 a, b ,c, 对应的就是 nums[i],nums[left],nums[right]
首先是对a的去重:假设不去重,第一次遍历到a时,固定 i ,left和right会遍历完i之后的数,并且寻找和为-a的组合,这一步没有问题; 接下来遍历到i+1,对应的值也为a,同理,left和right会遍历完i+1之后的数,并且寻找和为-a的组合,这个遍历的区间相较于第一次遍历到a时(对应下标为i)的区间更小,也就是第一次遍历时找到的组合已经包括第二次遍历到a时找到的组合了。也就会导致重复,所以要对a去重。
其次是对b和c的去重:这时a已经是固定的了,假设不对b去重,那么接下来要找的c就是值为-(a+b)的值,那么如果b有重复的,就会导致找到相同的c,也就会导致最终有重复的组合。c的去重同理。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
#先进行排序,非降序
res =[]
nums.sort()
#从左开始遍历
for i in range(len(nums)):
#剪枝,如果第一个数已经大于0了就不需要往下判断了
if nums[i] > 0:
return res
#去重
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 = right -1
elif (nums[i]+nums[left]+nums[right]) < 0:
left = left + 1
else:
res.append([nums[i],nums[left],nums[right]])
#对left去重
while left<right and nums[left] == nums[left+1]:
left = left + 1
#对right去重
while left<right and nums[right] == nums[right - 1]:
right = right - 1
left = left + 1
right = right - 1
return res
第18题. 四数之和
文档讲解:代码随想录
这个题与上面一个题的区别是:
①寻找四数之和,那么就要固定2个,然后再遍历left和right
②目标值不再是0了。不要判断nums[k] > target
就返回了,三数之和 可以通过 nums[i] > 0
就返回了,因为 0 已经是确定的数了,四数之和这道题目 target是任意值。比如:数组是[-4, -3, -2, -1]
,target
是-10
,不能因为-4 > -10
而跳过。因为目标值可能是负数,本质上就是再加上一个数有可能导致和是减少的,上一题中。如果当前值大于0,暗示了后面的都是正数了,加起来肯定会增加。这会导致剪枝操作有变化
注意:去重的操作与三数之和差不多,剪枝的地方要注意,尤其是对j的剪枝
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
res = []
for i in range(len(nums)):
#对i的剪枝,nums[i] 如果大于0且大于target了,那么数组后面的值都会大于target且大于0
if nums[i] > target and nums[i]>0:
return res
###对i去重
if i >0 and nums[i] == nums[i - 1]:
continue
for j in range(i+1,len(nums)):
#对j剪枝,nums[i]+nums[j]大于0并且大于target了,那么nums[j]肯定大于0,从j开始后面都是0,也就不用再
#遍历后面的left和right了
#但是不能直接return,这里只是说明j已经遍历到数组的尾部了,但是i还要继续遍历
if nums[i]+nums[j] > target and target>0: #这里有问题,需要注意要break而不是return
# return res
break
#对j去重,j要大于i+1才可以,i+1是j遍历的第一个数,从第二个开始判断
if j > i+1 and nums[j] == nums[j-1]:
continue
left = j + 1
right = len(nums) - 1
while left < right:
if nums[i]+nums[j]+nums[left] + nums[right]>target: #注意这里是target
right = right - 1
elif nums[i]+nums[j]+nums[left] + nums[right]<target:
left = left + 1
else:
res.append([nums[i],nums[j],nums[left],nums[right]])
#对left的去重
while left <right and nums[left] == nums[left+1]:
left = left + 1
##对right的去重
while left <right and nums[right] == nums[right-1]:
right = right - 1
left = left + 1
right = right - 1
return res