三数之和 三种解法(Python)

本文探讨了LeetCode中三数和为零问题的暴力求解方法,并介绍了两种优化策略:利用dict降低时间复杂度至O(N^2),以及结合排序与双指针优化至O(N^2)。通过实例展示了如何提高算法效率,避免超时问题。
摘要由CSDN通过智能技术生成

LeetCode链接

暴力求解 时间复杂度O(N^3)

会超时。。。。

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        res = []
        distinct_dict = {}
        for i in range(len(nums) - 2):
            for j in range(i + 1, len(nums) - 1):
                for k in range(j + 1, len(nums)):
                    if nums[i] + nums[j] + nums[k] == 0:
                        res_item = [nums[i], nums[j], nums[k]]
                        res_item.sort()
                        if tuple(res_item) not in distinct_dict:
                        	# 使用 int tuple作为dict的key进行去重
                            res.append(res_item)
                            distinct_dict[tuple(res_item)] = 1
        return res

使用dict替代第三重循环 直接查找对应的数字 时间复杂度 O(N^2)

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        res = []
        # 排序减少重复
        nums.sort()
        # 相同的值 会保留后面的索引
        value_by_index = {nums[i]: i for i in range(len(nums))}
        for i in range(len(nums) - 2):
            # 值和之前相同则跳过
            if i > 0 and nums[i] == nums[i - 1]: 
                continue
            for j in range(i + 1, len(nums) - 1):
                # 值和之前相同则跳过
                if j > i + 1 and nums[j] == nums[j - 1]:
                    continue
                c = - (nums[i] + nums[j])
                c_index = value_by_index.get(c)
                # 类似第三重循环 找到的值 下标需要大于j
                if c_index and c_index > j:
                    res.append([nums[i], nums[j], nums[c_index]])
        return res

排序+双指针 时间复杂度O(N^2)

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        res = []
        # 排序 数字由小到大
        # 固定k i j 之后 若三数之和小于0 则右移i 反之左移j
        # 移动的时候若元素值和之前相同则跳过
        nums.sort()
        for k in range(len(nums) - 2):
            # 排序过 数字由小到大 若k已经大于零 则后面都是正数 不可能和为0
            if nums[k] > 0:
                break
            # k右移 如果和之前的值相同则continue 相当于k += 1
            if k > 0 and nums[k] == nums[k - 1]: continue
            # 双指针左右夹逼
            i, j = k + 1, len(nums) - 1
            while i < j:
                s = nums[k] + nums[i] + nums[j]
                if s < 0:
                    # 和小于零 i右移到更大的值上面 提升和
                    i += 1
                    # i右移 和左值比较 相等则跳过
                    # 注意大前提 i < j
                    while i < j and nums[i] == nums[i - 1]: i += 1
                elif s > 0:
                    j -= 1
                    while i < j and nums[j] == nums[j + 1]: j -= 1
                else:
                    res.append([nums[k], nums[i], nums[j]])
                    # 和为0的情况 记录
                    # 之后 i,j 需要同时内移 并跳过相同的值
                    i += 1
                    while i < j and nums[i] == nums[i - 1]: i += 1
                    j -= 1
                    while i < j and nums[j] == nums[j + 1]: j -= 1
        return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值