Leetcode Blind75 | Three Sum | Two Sum

Two Sum

  • 网址

  • 给定一个目标数target,从数组里找到两个相加=target的值,返回她们的下标。


     

两个思路

  • 一个是数组有什么数,从左向右遍历,固定一个数A,然后分别与其他值看 A+B=target? ;


     
  • 一个是我们需要什么,固定一个数A,用 target-A 看我们需要的值B是什么,从左向右遍历,每个值和对应下标记录在preMap表里,同时从左向右做这样的计算,B 从preMap表里找。


     
  • 显然前者非常麻烦,最糟糕的时间复杂度为O(n^2),需要遍历嵌套数组;后者的简便之处在 1. 不需要反复做是否=target的比较,2.当比较一个值时,我们可以确定这个值前面的所有值都被比较并录入preMap中,通过空间换时间,将时间复杂度从O(n)降到了O(1)

coding

  • 输入
    • 给定的整数列表 nums 类型: List[int]
    • 给定目标值 target 类型:int
  • 输出
    • 两个数的数组下标,所以是一个整数列表,没找到符合条件的就是空列表
  • 变量
    • prevMap 哈希表,用于存储已经遍历过的值和对应索引
    • enumerate是pyhthon内置函数,返回索引和对应值,for循环遍历此结果需要两个变量:i (探当前索引) 和 n (探当前值)
    • diff 计算目标与当前元素的差值
  • 算法/语句
  • twoSum函数定义
    • 新建PrevMap变量
    • for循环遍历给定数组,看每个元素的值和索引
      • 每个元素:与目标值差值 diff = target-n
      • 在prevMap表找差值
        • 找到了就返回两个数索引:if语句
        • 找不到存储值&索引备着 prevMap[n] = i ;
      • 遍历完都没找到返回空列表:return语句

Three Sum

给定数组,找到三个相加=0的数,返回一组元素值

思路1

暴力破解,3个for循环嵌套;

3 nested loops and brute forcing

思路2

1. 3 Sum 转化为 2 Sum 中的两个数:i +target

  • 元素 i 是我们在 3Sum 问题中固定的一个元素。
  • target 是剩余两个元素之和达到的目标值,这个值等于 -i

2. 双指针方法

target不是做哈希映射,而是拆成两个指针 left right( j 或者 k)

3. 与旋转数组的相似(Leetcode33和153):排序查找

在旋转排序数组中,尽管数组被旋转,一部分仍然保持排序,这就是解决问题的线索。3Sum虽然与其方法不同(二分搜索 vs 双指针),但核心思想是一致的:利用数组的排序(或部分排序)特性来指导搜索策略。旋转排序数组是中间值与target比较,移动两端指针缩小搜索区间;3Sum是元素和与target比较,决定向内移动左指针还是右指针

  • 排序

  • 固定i/ 元素和与target比较/ 移动 jK

4. 与 2 Sum的不同点

在2Sum中,哈希表用于快速查找配对元素

但在 3Sum 问题中:

  • 不是使用哈希表来找到配对的元素。
  • 相反,利用数组已经被排序的事实。我们使用双指针方法,移动两个指针(通常称为 leftright),根据它们指向元素的和与 target 的比较结果来决定如何移动这些指针。

Coding

输入:给定数组

输出:3Sum数组

变量:

  1. 3Sum数组res[],用于找到三元组
  2. l 和 r 是比二分搜索更简便的端点双指针,在排序后的数组中寻找元素值符合 nums[l] + nums[l] + a = 0
  3. 用于检查重复的三元组:i 与 a在for循环中
    • i 是通过enumerate函数获得的当前元素的索引。i 标识了当前正在处理的nums列表中的元素位置
    • a是enumerate函数返回的当前元素值,即nums列表在索引 i 处的值【每轮迭代的固定值】
  1. 当前总和ThreeSum,与目标总和0比较,决定双指针方向

算法/语句

  • 新建三元组变量
  • 数组排序
  • for循环遍历数组nums,i 索引 a元素值
    • 判断是否重复:a== nums[i-1]-->i-1有效-->需要i>0
      • 重复continue语句跳出此次循环
    • 初始化双指针 l 和 r
      • 初始化放在continue后面:只有确定当前a不导致重复三元组,后续的查找操作才有必要才需要初始化 l 和 r【减少计算量优化算法性能】
    • while循环,判断条件l<r
      • 计算当前总和threeSum
      • 当前总和与目标总和0的比较:
        • >0 ---> 根据升序特点,总和需要变小,r指针往左移
        • <0 ---> 升序,总和需要变大,l 指针往右为大
        • ==0--->找到三元组
          • 添加到结果列表:用.append()方法把nums中选中的a, nums[l], nums[r]导入 res数组中
          • 寻找下一个可能的三元组: 移动左指针 l + 1 = l
          • 确保跳过所有与当前 l 相同的指向元素值:while循环
            • nums[l] == nums[l-1]--->bug(详见
              • 重复就移动L
class Solution(object):
    def threeSum(self, nums):
        res=[]
        nums.sort()

        for i,a in enumerate(nums):
            # 判断是否有重复值,后续l和r服务的查找操作才有意义
            if a==nums[i-1] and i>0:
                continue

            l, r = i+1, len(nums)-1 # i 是每轮固定值,不是l不是从头遍历而是为了凑target从i后面第一个位置遍历

            #遍历数组,寻找可能的三元组
            while l<r:
                threeSum = a + nums[l] + nums[r]
                #当前总和与0的比较
                if threeSum > 0:
                    r = r-1
                elif threeSum < 0:
                    l = l+1
                else:
                    res.append([a,nums[l],nums[r]])
                    l = l+1
                    while l<r and nums[l]==nums[l-1] :
                        l = l+1
        return res

零工 knowledge

3SUM确保不会有重复的单元组添加到结果中:

  1. 遍历+取值:enumerate 是一个内置函数,在遍历一个序列时同时获取元素的索引和值。
  2. 比较+决策:if-continue跳过重复值所在循环
  3. 为什么不是 append(a, nums[l], nums[r])?
  • 在Python中,list.append(x) 方法接受一个参数 x 并将其添加到列表的末尾。如果你想添加多个元素,你需要将它们作为一个单独的元素(比如一个元组或列表)传递给 append。所以,append([a, nums[l], nums[r]]) 将整个三元组 [a, nums[l], nums[r]] 作为一个列表元素添加到列表中。如果使用 append(a, nums[l], nums[r]),Python会抛出错误,因为 append 只接受一个参数。
  1. and 和 && 的区别?
  • 在Python中,逻辑与操作用 and 表示。&& 是其他编程语言(如C、C++、Java)中的逻辑与操作符。在Python代码中使用 && 会导致语法错误。所以在Python中,应该使用 and。
  1. 为什么在 elif 有 while 循环筛除重复项,而 for 循环下第一个语句也是筛除重复项?
    • for 循环中的筛除重复项是针对每轮迭代的固定值 i ;elif 中则是针对每轮迭代为了凑target的指针 l
  1. Python中的 while 和 if 不能加括号?
    • 在Python中,whileif 语句后的条件表达式不需要括号。这与其他一些语言(如C、C++、Java)不同,但如果你认为这样做可以提高代码的可读性,你也可以添加它们。例如,if (x > 0): 在Python中是有效的,括号是可选的。

Bug

l 必然>0,因为即便最开始时固定值i占了0下标,l 不可能<0;

给出的错误提示 IndexError: list index out of range 通常意味着代码试图访问一个不存在的索引。即确保 l 增加不超过最大索引,l < r

  • 22
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值