Leetcode 15. 三数之和 Python题解

发布时间 2023-04-24 17:18:07作者: venas

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


1. 排序+双指针

解题思路:

一开始想到暴力破解法,使用三重循环寻找和为0的3个元素,在此期间使用集合来去重。这样做的时间复杂度为O(n^3),空间复杂度为O(n)。提交之后发现会超时。此路不通。
现在把题解根据自己的理解梳理一遍。
为了解决重复的问题,可以考虑排序,使得:第二层循环的起始值不小于第一层循环;第三层循环起始值不小于第二层循环。这样就避免了(a,b,c)以(b,a,c)、(c,a,b)等形态出现在结果中。
这道题和Leetcode 1.两数之和类似,为了降低三重循环的时间复杂度,可以使用双指针。在第二重循环中,由于二重循环是从小到大遍历,b是不断增加的,则b<b';在满足a+b+c=0的条件下,c应该相应的减少,即c'<c。使用双指针能够将时间复杂度降低为O(n),因为在长度为n的数组上,左指针每移动一个位置,右指针可以移动剩余的n个位置,均摊时间复杂度为O(n)。如何理解并使用双指针?双指针将O(n^2)降为O(n),并不是表示只用两个循环,而是通过双指针均摊了时间复杂度,仍然可以使用3个循环。双指针首先固定一端,通过适当的条件移动另一端,移动结束后才对是否满足目的进行判断。

用到的知识:
双指针:当我们需要枚举数组中的两个元素时,其中的一个元素递增,而另一个元素递减时,就可以使用双指针的方法,将时间复杂度从O(n^2)降低为O(n)。为什么是O(n)呢?因为在移动的过程中,左指针向右移动一个位置,而右指针向左移动若干个位置,所移动的位置和数组的长度相关,往往为n,均摊下来,时间复杂度就是O(n)。

提交代码:

复杂度分析:

  1. 时间复杂度:首先排序的时间复杂度是O(N·log N),而查找三数之和的时间复杂度是O(N2),因此最终的时间复杂度去两者之间的最大值为O(N2);
  2. 空间复杂度:不考虑存储答案的空间的情况下,排序的空间复杂度为O(log N);我们还修改了原数组nums,往往这是需要通过一个额外的O(N)的数组空间来实现的,因此空间复杂度应该为O(N)。

2. 题目描述

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。

注意:输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。