Leetcode 018 四数之和 思路详解+反思易错 Python实现

本人一直在努力地积累Leetcode上用Python实现的题,并且会尽力讲清每道题的原理,绝不像其他某些博客简略地带过。
如果觉得讲的清楚,欢迎关注。



给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:

答案中不可以包含重复的四元组。

示例:

给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

满足要求的四元组集合为:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]


思路:很明显。四数之和与三数之和很像,但当我用四指针夹逼来做时发现超时了,但却有大神写的能通过。这说明就算是相同的算法,代码的冗杂程度也会很大程度上影响性能。所以说夹逼遍历,最重要的就是过滤!过滤!过滤!怎样把一定不符合条件的值跳过才是最能提升性能的。

但是先来看看我提交的代码:

1.字典查找法

总思路:把N4拆成2个N2。第一个for循环,先求后2个值可能的取值的所有情况,并且把它们储存在一个字典里,以和作为键。

第二个for,我们遍历前2个值所可能取的各种值,算出和并且检查target - onesum是否在我们的字典里,如果在,就说明我们找到了一个解。其实这种求几数之和的问题,都可以通过这种思路。比如说三数之和,现在我就想到根本不必用指针,算出所有后2个值所加的可能的和,然后用字典存,最后用target-第一个值去检查是否存在这样的键。

class Solution:
    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        nums.sort()
        ans = set()
        sumans = {}
        if len(nums) < 4:
            return []
        for i in range(2, len(nums) - 1):
            for j in range(i+1, len(nums)):
                onesum = nums[i] + nums[j]
                if onesum not in sumans:
                    sumans[onesum] = [(i, j)]
                else:
                    sumans[onesum].append((i, j))
        for i in range(len(nums) - 3):
            for j in range(i+1, len(nums) - 2):
                onesum = nums[i] + nums[j]
                if target - onesum in sumans:
                    for k in sumans[target - onesum]:
                        if k[0] > j:
                            ans.add((nums[i], nums[j], nums[k[0]], nums[k[1]]))
        return [i for i in ans]


虽然说我们写出夹逼的方法,但确实有人写出了而且比我快,我们主要分析一下他们是怎么设置过滤条件的。

2.四指针夹逼法

class Solution:
    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        

        if not nums:
            return []
        
        _4_sum_list = []
        nums.sort()
        if nums[-1]*4 < target:
            return []
        for i in range(len(nums)-3):
            if nums[i]*4 > target:
                break
            if i==0 or nums[i]!= nums[i-1]:
                ele = nums[i]
                target_3_sum = target - ele
                if nums[-1]*3 < target_3_sum:
                    continue
                for j in range(i+1,len(nums)-2):
                    ele2 = nums[j]
                    if ele2*3 > target_3_sum:
                        break
                    if j==i+1 or ele2!= nums[j-1]:
                        target_2_sum = target_3_sum - ele2
                        point_left = j+1
                        point_right = len(nums)-1
                        while point_left < point_right:
                            if nums[point_left] + nums[point_right] > target_2_sum:
                                point_right -= 1
                            elif nums[point_left] + nums[point_right] < target_2_sum:
                                point_left += 1
                            else:
                                aaa = [ele, ele2,nums[point_left], nums[point_right]]
                                _4_sum_list.append(aaa)
                                point_left += 1
                                point_right -= 1
                                while point_left < point_right and nums[point_left] == nums[point_left-1]:
                                    point_left += 1
                                while point_left < point_right and nums[point_right] == nums[point_right+1]:
                                    point_right -= 1


        return _4_sum_list

首先思路很清晰,i,j,point_left,point_right四个指针。

注意 因为经过了排序,i到point_right递增。

1.如果i也就是第一个指针的四倍大于等于target, break

2.如果最大一项的三倍小于还需要填充的和,则进入下个更大的i。

3.同理它这里的if保证了不重复计算相同的i.

4。剩下来的思路与三数之和大致相同。具体可参考我的另一篇博客。https://mp.csdn.net/postedit/80647482



反思总结:1.用字典查找法。先遍历求出后几个值的可能取值,并用字典去存储,最后去搜索target - nums[i]-nums[j]。

2.夹逼法。定4个指针,后2个指针用来夹逼。最重要的是要会过滤条件,否则它就是暴力法。

猜你喜欢

转载自blog.csdn.net/weixin_41958153/article/details/80687958
今日推荐