代码随想录Day7: 454 四数相加 | 15 三数之和 | 18.四数之和

454 四数相加II

思路:

注意: 什么时候需要去重, 什么时候不需要: 之前的4sum 和3sum都是在同一个array中,然后题目要求unique的组合, 所以需要去重。但是这里是在不同的数组中找出组合,所以不需要去重。

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        # 这道题要看a + b + c + d = 0, 有多少个组合
        # 因为是在不同的subarray中定位, 所以不需要像在同一个array中找index那样去重
        # a + b = -(c + d)
        # 创建用哈希映射来存储 a+b的结果和其频次

        hashmap = dict()

        for n1 in nums1:
            for n2 in nums2:
                if n1 + n2 in hashmap:
                    hashmap[n1+n2] += 1
                else:
                    hashmap[n1+n2] = 1
        
        # 如果 -(a+b) 在nums3 和 nums4中, count += hashmap[key]
        count = 0
        for n3 in nums3: 
            for n4 in nums4:
                key = -(n3 + n4)
                if key in hashmap:
                    count += hashmap[key] # 为什么这里是 + value呢, 因为
                    # a[1] + b[2] = 5
                    # a[2] + b[3] = 5
                    # a[3] + b[4] = 5, 
                    # 然后c[1] + b[2] = -5, 在hashmap中 上面的5出现了3遍
                    # 这会有3个组合满足四个数相加 = 0, 所以count加的是hashmap中的value, 就是出现的次数
        
        return count 

15. 三数之和

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        # 用2 pointer的思路,nums[i] + left + right = 0, 注意不能有重复的组合,所以去重很重要
        nums = sorted(nums)
        
        ret = [] # 2d array 存最后的unique 组合

        for i in range(len(nums)):
            if nums[i] > 0:
                return ret # nums是升序排序, 如果第一个数已经>0了,后面的数肯定都大于第一个, 那么不可能相加还=0了
                
            # 当 i 不为第一个数, 当前的数和前面的数一样的话, 就跳过,    
            if( i > 0 and nums[i] == nums[i-1]): # 这里为什么不是 nums[i] == nums[i+1] 比较呢,因为如果i和i+1相等就跳过的话就会丢失-1,-1,2这种组合
                continue #跳过

            l = i + 1
            r = len(nums) - 1 

            while (l < r):# l 不能等于 r, 因为当l = r 的时候, 他们都指向的同一个数, 但我们需要两个数 和nums[i] 拼凑
                if (nums[i] + nums[l] + nums[r] < 0):
                    l+=1 # 左边太小了, 要增大
                elif (nums[i]+ nums[l] + nums[r] > 0):
                    r -= 1 # 右边太大了,减小
                else:
                    ret.append([nums[i], nums[l], nums[r]]) 
                    # 同理: 万一是 0,-1,-1,-1,1,1,1 的情况,得对l 和r进行去重    
                    while (l < r and nums[l] == nums[l+1]): #l 向右跳
                        l += 1
                    while (l < r and nums[r] == nums[r-1]): # r向左跳
                        r -= 1
                    r -= 1
                    l += 1
                # print(ret)

        # print('null')
        return ret

18.四数之和 

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        
        ret = []

        # 概念图
        # [1,0,-1,0,-2,2]
        #  k i  L      R
        for k in range(len(nums)):
            # 一级剪枝:
            if(nums[k]>target and nums[k] > 0 and target > 0 ): 
                break
            # 一级去重
            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 and nums[k] + nums[i] > 0:
                    break
                # 二级去重
                if( i > k + 1 and nums[i] == nums[i-1]):
                    continue

            # 和3sum一样的挪l和r使四数之和 = target, 然后l和r要去重
                l = i + 1
                r = len(nums) - 1

                while l < r:
                    s = nums[k] + nums[i] + nums[l] + nums[r]
                    if s == target:
                        ret.append([nums[k], nums[i], nums[l], nums[r]])
                        while l < r and nums[l] == nums[l+1]:
                            l += 1
                        while l < r and nums[r] == nums[r-1]:
                            r -= 1
                        l += 1
                        r -= 1
                    elif s < target:
                        l += 1
                    else:
                        r -= 1 
                    # print(ret)
        return ret

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值