15. 三数之和
利用双指针或哈希表简化数组处理
15.题目链接-来源:力扣(LeetCode)(中等)
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
思路:
暴力解法就不谈了,很直白但是肯定超时。至少需要优化到O(n²)才可能通过。
注意到要求三元组不可重复,这种时候显然就需要排序了,不然你怎么记得自己存没存过这个答案。一开始心头一惊,一般排序要用快排,实现起来还是蛮繁琐的(要写个寻找pivot然后递归的辅助函数)。然后想起来 Arrays.sort() 这个小东西,对java的基本类型采用的是快排,于是直接拿来。
接下来看看能不能从暴力O(n³)简化到O(n²)。
上一篇笔记提过这种组合查找的题目自然而然想到用哈希表查找,把某一层O(n)的遍历降为O(1)。用一个HashSet记录一遍表中的元素,那么直接枚举前两个数,然后哈希查找第三个数。注意细节,对于 [-4,2,3],我们前两层得到[-4,2,],第三个元素用哈希搜索的话,是会得到2的,但是我们只有一个2,显然是不对的。这里如果要求 v3 > v2的话也不行,因为这样无法处理[-4,2,2],遂放弃哈希表。
然后看了题解才知道用双指针,感觉这里没见过这类题的话不容易想到,以后就知道这样用了,双指针跟哈希表一样也适用于这类把O(n²)遍历简化为O(n)的问题。不同的是,双指针处理可能有重复的元素更加容易一些,因为能记录下标信息,不会搞混。遍历数组得到第一个元素v1,对每一个v1之后的元素用双指针向中间查找,因为我们排过序了所以v2坐标向右增长一定是不递减的,v3一定是不递增的,所以三者之和大于0就是收缩v3下标,否则增长v2下标,直到相遇或者满足和等于0,跳出。
时间复杂度:O(n²)
空间复杂度:O(m) m是一个接近 $C_n^3$ 的数
实现:
1 | class Solution { |