代码随想录算法训练营第七天 |● 454.四数相加II ● 383. 赎金信 ● 15. 三数之和 ● 18. 四数之和

本文介绍了三个使用哈希表和双指针解决的数组求和问题:四数相加II、赎金信和三数之和。在四数相加II中,通过构建哈希表统计两数之和的出现次数;赎金信问题通过哈希表检查字符是否足够;三数之和利用排序和双指针去除重复项。所有问题的关键在于有效去重和优化搜索过程。
摘要由CSDN通过智能技术生成

● 454.四数相加II

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        hash={}
        for i in nums1:
            for j in nums2:
                if i+j not in hash:
                    hash[i+j]=1
                else:
                    hash[i+j]+=1
        res=0
        for k in nums3:
            for l in nums4:
                if 0-k-l in hash:
                    res+=hash[0-k-l]
        return res

● 383. 赎金信 

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        hash1={}
        for i in magazine:
            if i not in hash1:
                hash1[i]=1
            else:
                hash1[i]+=1
        for i in ransomNote:
            if i not in hash1:
                return False
            else:
                hash1[i]-=1
                if hash1[i]<0:
                    return False
        return True
        

● 15. 三数之和

关键在于去重

法一:哈希法

两重for 循环,一重便利a,一重便利b,再寻找0-a-b,用哈希没有顺序,去重会比较麻烦。

法二:双指针

for 循环遍历i,得到a

left,right

对数组进行排序,没有要求返回下标,所以可以排序。

如果nums[i]+nums[left]+nums[right]>0,right往左移一位

<0 ,left往右移

==0,得到num[i],nums[left],nums[right]

难点:去重

i,left,right可能有重复值,所以需要去重。

代码实现

result=[] 存放结果集

sort()排序

if nums[i]>0 return 

难点:判断nums[i]==nums[i+1] continue,结果集中有重复会直接跳过

例如[-1,-1,2]不在结果集中

还是nums[i]==nums[i-1]  continue,left,right不受影响

elif i>0 and nums[i]==nums[i-1]   (对a的去重)

     continue

left=i+1

right=len(n)-1

while right>left 边界问题尝试带入,right=left,说明b和c为同一个值

0 -1 -1 -1 1 1 1

得到的结果集仍然需要去重,收获结果集后面

if right>left  right[i]==right[i-1] right-=1 (对c的去重)

if  right>left  left[i]==left[i+1] left+=1 (对b的去重)

持续向中间移动

结果集0000

放在 while left <right 后面会无法收获结果集

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        result=[]
        nums.sort()
        n=len(nums)
        for i in range(n):
            left=i+1
            right=n-1
            if nums[i]>0:
                return result 
            if i>0 and nums[i]==nums[i-1]:
                continue           
            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 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

18.四数之和

比三数之和再套一层循环k

for k

for i

left,right

剪枝和去重是难点

如何对k进行剪枝:

nums[i]>target 剪枝:错误,两个负数相加可能会变得更小。

-4,-1,0,0  target=-5

if nums[k]>target and nums[k]>0 and target>0:break

去重:

if k>0 and nums[k]==nums[k-1]: continue

for i=k+1 

同样可以剪枝

nums[k]+nums[i]是一个整体

因此nums[k]+nums[i]>targrt and nums[k]+nums[i]>0 and arget>0:break

去重:

if i>k+1 (因为i=k+1开始的)and nums[i]==numd[i-1]:continue

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        result = []
        nums.sort()
        
        for i in range(len(nums)):
            # 如果第一个元素已经大于0,不需要进一步检查
            if nums[i]>target and nums[i] > 0 and target>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 and target>0:
                    break
                if k>i+1 and nums[k] == nums[k - 1]:
                    continue
                left = k + 1
                right = len(nums) - 1
            
                while right > left:
                    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 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值