• Python练习题:实现三数之和


    题目

    给定一个包含 n 个整数的列表 nums,请判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组

    注意:答案中不可以包含重复的三元组。

    例如:

    给定一个列表:[-1, 0, 1, 2, -1, -4]
    返回结果:[(-1, -1, 2), (-1, 0, 1)]
    
    给定一个列表:[1, 2, 4]
    返回结果:[]
    
    给定一个列表:[-1, 0, 1, 2, -1, -4, 0, 2, 0, 4, -4, -2, -1, 2]
    返回结果:[(-4, 0, 4), (-4, 2, 2), (-2, 0, 2), (-1, -1, 2), (-1, 0, 1), (0, 0, 0)]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    实现思路1

    • 使用两层循环,第一层循环确定第一个数 a 的数值,第二层循环确定第二个数 b 的数值,然后第三个数 c = 0 - a - b ,我们只需判断 c 是否在列表中出现即可
    • 根据上面的思路,我们实现起来并不难,但请注意本题有一个要求:不可以包含重复的三元组,所以我们就需要进行去重处理,而这个去重的细节过程也正是本题的一大难点
    • 去重处理时,可以先找到所有符合条件的三元组,放到一个列表中,然后再去重,但这样的去重处理可能不太好弄,所以我们可以在确定 a、b、c 的数值时就对其可能的重复情况进行考虑

    代码实现1

    def threeSum(nums):
        res = []
        nums.sort()  # 排序
        for i in range(len(nums)):
            if nums[i] > 0:  # 排序后,如果第一个数 a 大于 0 ,那么必然不存在符合条件的三元组
                break
            if i > 0 and nums[i] == nums[i - 1]:  # 第一个数 a 去重
                continue
            tmp_set = set()
            for j in range(i + 1, len(nums)):
                # 从 j > i + 2 考虑,是因为允许有2种特殊情况: (1) a = b = c = 0; (2) a为负数,b = c 且 a + b + c = 0
                if j > i + 2 and nums[j] == nums[j - 1] and nums[j] == nums[j - 2]:  # 第二个数 b 去重
                    continue
                a, b, c = nums[i], nums[j], 0 - nums[i] - nums[j]
                if c in tmp_set:
                    res.append((a, b, c))
                    tmp_set.remove(c)  # 第三个数 c 去重
                else:
                    tmp_set.add(nums[j])
        return res
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    实现思路2

    • 使用 双指针 的方法来实现
    • 首先需要对 nums 按从小到大进行排序
    • 第一层循环,同样是确定第一个数 a 的数值,并且在这里就对 a 可能的重复情况进行处理
    • 接着定义两个指针:left、right,分别表示第二个数 b 和第三个数 c 的下标,left初始位置定义在 a 的下一个位置,right的初始位置定义在 nums 最后一个数的位置
    • 如果 a + b + c < 0,因为 nums 是排好序的,此时小于0,那么就说明 b 的数值太小了,需要让 b 增加,也就是 left 向右移动
    • 如果 a + b + c > 0,因为 nums 是排好序的,此时大于0,那么就说明 c 的数值太大了,需要让 c 减小,也就是 right 向左移动
    • 如果 a + b + c = 0,那么就说明当前三元组符合条件,把该三元组添加到最终结果中
    • 添加符合条件的三元组后,同样需要对 b、c 可能的重复情况进行考虑,确保最终结果中不会包含有重复的三元组

    代码实现2

    '''
    学习中遇到问题没人解答?小编创建了一个Python学习交流群:711312441
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    def threeSum(nums):
        res = []
        nums.sort()  # 排序
        for i in range(len(nums)):
            if nums[i] > 0:  # 排序后,如果第一个数 a 大于 0 ,那么必然不存在符合条件的三元组
                break
            if i > 0 and nums[i] == nums[i - 1]:  # 第一个数 a 去重
                continue
            left, right = i + 1, len(nums) - 1
            while left < right:
                a, b, c = nums[i], nums[left], nums[right]
                if a + b + c < 0:  # nums是排好序的,此时小于0,那么需要让 b 增加,left向右移动
                    left += 1
                elif a + b + c > 0:  # nums是排好序的,此时大于0,那么需要让 c 减小,right向左移动
                    right -= 1
                else:
                    res.append((a, b, c))
                    # a 在外层循环固定保持不变,所以找到一组符合条件的 b 和 c 后,left、right都需要移动
                    left += 1  # left向右移动
                    right -= 1  # right向左移动
                    while left < right and nums[left - 1] == nums[left]:  # 第二个数 b 去重
                        left += 1
                    while left < right and nums[right] == nums[right + 1]:  # 第三个数 c 去重
                        right -= 1
        return res
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
  • 相关阅读:
    前端面试:webpack整理
    并发编程之互斥锁
    输入输出管理:I/O控制方式
    【并发编程】并发工具类
    最新版傻妞及Web安装教程-2022.11.6
    麦克风阵列波束形成之DSB原理与实现
    【自然语言处理概述】文本词频分析
    JavaWeb(一)
    04-对原生app应用中的元素进行定位
    docker安装及优化
  • 原文地址:https://blog.csdn.net/qdPython/article/details/126179976