leetcode刷题记第18题解法(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]
]

来源:力扣(LeetCode)
链接: leetcode_18题.

解题

本次使用4种方法,在leetcode上还有更多的方法,只能说真牛逼,真聪明。

1. 使用二分法

2. 使用二分法的优化

3. 使用递归思路

4. 在二分法的优化上继续优化

===================================================

实现

// An highlighted block

class Solution:
    def fourSum(self, nums, target):
        '''
        三数之和的基础上变为四数之和  使用二分法
        '''
        nums.sort()
        res = []
        length = len(nums)
        for i in range(length):
            for j in range(i+1,length):
                l = j+1
                r = length-1

                while l<r:
                    end = target-nums[i]-nums[j]-nums[r]-nums[l]
                    if end == 0:
                        res.append([nums[i],nums[j],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 end > 0:
                        l += 1
                    else:
                        r -= 1
        return list(set(map(tuple, res)))


    def fourSum_1(self, nums, target) :
        '''
        第一种的优化
        '''
        nums.sort()
        length = len(nums)
        ans = []
        for i in range(length):
            for j in range(i + 1, length):
                l, r, t = j + 1, length - 1, target - nums[i] - nums[j]
                while l < r:
                    while l < r and t > nums[l] + nums[r]: l += 1
                    while l < r and t < nums[l] + nums[r]: r -= 1
                    if l < r and nums[l] + nums[r] == t:
                        ans.append([nums[i], nums[j], nums[l], nums[r]])
                    l += 1
        return list(set(map(tuple, ans)))



    def fourSum_2(self, nums, target):
        '''

        在三数之和的时候使用这种方法是可以的  但是四数之和就超时了
        '''
        import itertools

        ts, bs = [i for i in set(list(itertools.combinations(nums, 4))) if
                  sum(i) == target], {}  # 求出所有的组合  然后  set 去重  判断等于0 的加入ts
        for i in ts:
            '''
            >>frozenset((-1, 0, -1))
            frozenset({-1, 0})
            输入 [-1, 0, 1, 2, -1, -4]
            输出{frozenset({2, -1}): (-1, 2, -1), frozenset({0, 1, -1}): (-1, 0, 1)}
            '''
            bs.update({frozenset(i): i}) if frozenset(i) not in list(bs.keys()) else 0  # 将字典的key作为 frozenset存储

        return list(bs.values())

    def fourSum_3(self, nums, target):
        '''
        递归思路
        这个其实修改  一下flag的值  就变成n数之和了

        '''
        def Sum(inp, target, flag):
            result = []

            if flag == 1:
                if target in inp:
                    return [[target]]
                else:
                    return
            else:
                for i in range(len(inp)):
                    if i != 0 and inp[i] == inp[i - 1]:
                        continue
                    temp = Sum(inp[i + 1:], target - inp[i], flag - 1)
                    if temp:
                        for item in temp:
                            item.append(inp[i])
                            result.append(item)
            return result

        nums.sort()
        return Sum(nums, target, 4)

    def fourSum_4(self, nums: List[int], target: int) -> List[List[int]]:
        '''
        速度最快的算法   秒杀前面的所有   击败99%的python用户
        '''
        result = []
        if not nums or len(nums) < 4:
            return []
        nums.sort()
        # 数组长度
        length = len(nums)
        # 定义4个指针k,i,j,h  k从0开始遍历,i从k+1开始遍历,留下j和h,j指向i+1,h指向数组最大值
        for k in range(length - 3):
            # 当k的值与前面的值相等时忽略
            if k > 0 and nums[k] == nums[k - 1]:
                continue
            # 获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏
            min1 = nums[k] + nums[k + 1] + nums[k + 2] + nums[k + 3]
            if min1 > target:
                break
            # 获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略
            max1 = nums[k] + nums[length - 1] + nums[length - 2] + nums[length - 3]
            if max1 < target:
                continue
            for i in range(k + 1, length - 2):
                if i > k + 1 and nums[i] == nums[i - 1]:
                    continue
                j = i + 1
                h = length - 1
                min2 = nums[k] + nums[i] + nums[j] + nums[j + 1]
                if min2 > target:
                    continue
                max2 = nums[k] + nums[i] + nums[h] + nums[h - 1]
                if max2 < target:
                    continue
                # 开始j指针和h指针的表演,计算当前和,如果等于目标值,j++并去重,h--并去重,当当前和大于目标值时h--,当当前和小于目标值时j++
                while j < h:
                    curr = nums[k] + nums[i] + nums[j] + nums[h]
                    if curr == target:
                        result.append([nums[k], nums[i], nums[j], nums[h]])
                        j += 1
                        while j < h and nums[j] == nums[j - 1]:
                            j += 1
                        h -= 1
                        while j < h and i < h and nums[h] == nums[h + 1]:
                            h -= 1
                    elif curr > target:
                        h -= 1
                    elif curr < target:
                        j += 1

        return result


print(Solution().fourSum_3([1, 0, -1, 0, -2, 2],0))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值