[leetcode: Python]18.4Sum

本文探讨了如何寻找数组中四个数相加等于特定目标值的所有唯一组合,并提供了三种高效解决方案,利用排序与哈希表等技巧降低时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note: The solution set must not contain duplicate quadruplets.

For example, given array S = [1, 0, -1, 0, -2, 2], and target = 0.

A solution set is:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

题意:从数组中找到4个数,使它们的和为target。要求去重,可能有多组解,需要都找出来。

解题思路:一开始想要像3Sum那样去解题,时间复杂度为O(N^3),可无论怎么写都是Time Limited Exceeded。而同样的算法使用C++是可以通过的。说明Python的执行速度比C++慢很多。还说明了一点,大概出题人的意思不是要让我们去像3Sum那样去解题,否则这道题就出的没有意义了。这里参考了kitt的解法:http://chaoren.is-programmer.com/posts/45308.html

     需要用到哈希表的思路,这样可以空间换时间,以增加空间复杂度的代价来降低时间复杂度。首先建立一个字典dict,字典的key值为数组中每两个元素的和,每个key对应的value为这两个元素的下标组成的元组,元组不一定是唯一的。如对于num=[1,2,3,2]来说,dict={3:[(0,1),(0,3)], 4:[(0,2),(1,3)], 5:[(1,2),(2,3)]}。这样就可以检查target-key这个值在不在dict的key值中,如果target-key在dict中并且下标符合要求,那么就找到了这样的一组解。由于需要去重,这里选用set()类型的数据结构,即无序无重复元素集。最后将每个找出来的解(set()类型)转换成list类型输出即可。

方法一:222ms

class Solution(object):
    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        ln = len(nums)
        res = set()
        dict = {}
        if ln < 4:
            return []

        nums.sort()
        for  p in range(ln):
            for q in range(p+1, ln):
                if nums[p] + nums[q] not in dict:
                    dict[nums[p] + nums[q]]=[(p, q)]
                else:
                    dict[nums[p] + nums[q]].append((p, q))
        for i in range(ln):
            for j in xrange(i+1, ln-2):
                T = target - nums[i] - nums[j]
                if T in dict:
                    for k in dict[T]:
                        if k[0] > j:
                            res.add((nums[i], nums[j], nums[k[0]], nums[k[1]]))
        return [list(i) for i in res]

方法二:132ms

class Solution(object):
    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        ret = []
        nums.sort()
        length = len(nums)

        if length < 4:
            return []

        for item_idx in xrange(length - 3):
            if target < nums[item_idx] * 4 or target > nums[-1] * 4:
                break

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

            item_idx_base = item_idx + 1
            for i in xrange(item_idx_base, length - 2):
                if target - nums[item_idx] < nums[i] * 3 or target - nums[item_idx] > nums[-1] * 3:
                    break

                if i > item_idx_base and nums[i - 1] == nums[i]: 
                    continue

                left = i + 1
                right = length - 1

                while (left < right):
                    sum_val = (nums[item_idx] + nums[i] + nums[left] + nums[right]) - target
                    if sum_val < 0:
                        left += 1
                    elif sum_val > 0:
                        right -= 1
                    else:
                        ret.append([nums[item_idx], nums[i], nums[left], nums[right]])
                        while(left < right and nums[left] == nums[left + 1]):
                            left += 1
                        left += 1
        return ret

方法三:103ms
这个方法很厉害啊。。。findNSum

class Solution(object):
    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        # res = []
        # nums.sort()
        # for i in range(len(nums) - 3):
        #     if i > 0 and nums[i] == nums[i - 1]:
        #             continue
        #     flag = 0
        #     for j in range(i + 1, len(nums) - 2):
        #         if flag == 1 and nums[j] == nums[j - 1]:
        #             continue
        #         flag = 1
        #         l, r = j + 1, len(nums) - 1
        #         while l < r:
        #             s = nums[i] + nums[j] + nums[l] + nums[r]
        #             if s < target:
        #                 l += 1
        #             elif s > target:
        #                 r -= 1
        #             else:
        #                 res.append([nums[i], nums[j],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
        # return res 

        def findNSum(nums, target, N, result, results):
            if len(nums) < N or N < 2 or target < nums[0] * N or target > nums[-1] * N:
                return 
            if N == 2:
                l, r = 0, len(nums) - 1
                while l < r:
                    s = nums[l] + nums[r]
                    if s > target:
                        r -= 1
                    elif s < target:
                        l += 1
                    else:
                        results.append(result + [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    
            else:
                for i in range(len(nums) - N + 1):
                    if i == 0 or (i > 0 and nums[i] != nums[i - 1]):
                        findNSum(nums[i+1:], target-nums[i], N - 1, result + [nums[i]], results)
        results = []
        findNSum(sorted(nums), target, 4, [], results)
        return results
class Solution(object):
    def fourSum(self, nums, target):
        nums.sort()
        results = []
        self.findNsum(nums, target, 4, [], results)
        return results

    def findNsum(self, nums, target, N, result, results):
        if len(nums) < N or N < 2: return

        # solve 2-sum
        if N == 2:
            l,r = 0,len(nums)-1
            while l < r:
                if nums[l] + nums[r] == target:
                    results.append(result + [nums[l], nums[r]])
                    l += 1
                    r -= 1
                    while l < r and nums[l] == nums[l - 1]:
                        l += 1
                    while r > l and nums[r] == nums[r + 1]:
                        r -= 1
                elif nums[l] + nums[r] < target:
                    l += 1
                else:
                    r -= 1
        else:
            for i in range(0, len(nums)-N+1):   # careful about range
                if target < nums[i]*N or target > nums[-1]*N:  # take advantages of sorted list
                    break
                if i == 0 or i > 0 and nums[i-1] != nums[i]:  # recursively reduce N
                    self.findNsum(nums[i+1:], target-nums[i], N-1, result+[nums[i]], results)
        return
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值