Day 26 - 15. 3sum

Day26 - 15.三数之和

LeetCode 15.三数之和

题目链接:

https://leetcode.cn/problems/3sum/arrow-up-right

1. 题目描述

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

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

举个例子:

输入: 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. 思路解析

本题是经典的双指针类型的问题,解决此问题的核心在于以下两点。

  1. 左右指针的移动策略。

  2. 结果的去重策略。

例如:对于 a + b + c = 0

此时一层循环固定 a,此时问题变为 找出 b+ c == -a,就可以转化为双指针问题。

首先对数组nums进行升序排序,类似「167.两数之和II」,本次使用三个索引:ileftright。初始值i = 0left = i + 1right = nums.size - 1

算法如下:

  1. nums[i] + nums[left] + nums[right] > targetnums[left]nums[right]需要一个更小的值,由于nums是升序的,故只能把索引right往左移,--right。如果left >= right,向右移动i,直到nums[i] != nums[i-1](对nums[i]去重)。

  2. nums[i] + nums[left] + nums[right] < targetnums[left]nums[right]需要一个更大的值,由于nums是升序的,故只能把索引left往右移,++left。如果left >= right,向右移动i,直到nums[i] != nums[i-1](对nums[i]去重)。

  3. nums[i] + nums[left] + nums[right] == target,把当前三元组存到结果数组中,并且left右移直到nums[left-1] != nums [left](对nums[left]去重)去寻找下一个满足条件的三元组。如果left >= right,向右移动i,直到nums[i] != nums[i-1](对nums[i]去重)。

  4. 如果i == nums.size(),算法结束。

3. C++代码

3.1. 暴力算法

老规矩,先上暴力!

暴力算法很容易想到,枚举三层变量...

关键是要处理好:

  • 无重复三元组

  • 边界条件

  • 特殊情况(数组本来就不满三个...等等)

复杂度,可预见的超时...

3.2. 双指针算法

复杂度虽然没有很出色:,但也够用。

关键是思路要打开,这个算法很好的把 三数之和 变为 两数之和,转化为双指针问题。

4. 复杂度分析

时间复杂度: 首先排序最快 O(nlogn),然后索引i遍历一遍字符串nums,针对每个i,都有leftright共同遍历一遍nums,总共需要 O(n2),故时间复杂度是 (nlogn) + O(n2) = O(n2)

空间复杂度: 主要是排序消耗的空间,看具体的排序算法,快排的话是O(logn),寻找三数之和的过程需要一个结果数组空间复杂度是O(n),故总的空间复杂度是O(n)

5. Redo. 02/04

双指针:左右指针收缩

预先排序:复杂度

去重操作:判断相邻元素是否相等

Last updated