这是我参与2022首次更文挑战的第39天,活动详情查看:2022首次更文挑战」
三数之和 3 Sum
LeetCode传送门15. 三数之和
题目
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.
Notice that the solution set must not contain duplicate triplets.
Example:
Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Input: nums = []
Output: []
Input: nums = [0]
Output: []
Constraints:
0 <= nums.length <= 3000
思考线
解题思路
这道题最能想到的就是使用三层for循环,然后把所有的值都找出来,本着先找出解再优化的原则,我写了如下代码
function threeSum(nums: number[]): number[][] {
const res: number[][] = [];
const resObj = {}
const len = nums.length;
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
for (let k = j + 1; k < len; k++) {
if (nums[i] + nums[j] + nums[k] === 0) {
const item = [nums[i], nums[j], nums[k]]
const ind = item.sort().join()
if (!resObj[ind]) {
res.push(item);
resObj[ind] = true;
}
}
}
}
}
return res
};
然而很明显这样的暴力解是会明显的超时的,那么我们该如何做这道题呢?
由于题目要求我们找出所有和为0且不能重复的三元组。我们首先思考一下如何能保证不重复呢?
经过简单的思考,保证不重复最好做的是把数组进行升序排序,我们只要保证first <= second <= third,这样我们再找三元组的时候就可以避免重复。
然后就是找到三数和为0如何优化的过程。
-
我们可以先遍历一遍排序后的数组,把第一个元素确定下来
-
如果第一个元素都大于0,后面的肯定也大于0,所以直接
break掉循环即可 -
如果当前元素
i和上一个元素i-1的值相等,说明这和上一个内容重复了,我们直接执行continue来提前结束掉当前循环
-
-
除去上面两种情况,我们再确定后面两个数,后面两个数,我们可以用双指针法来找到
sum===0的情况, 我们假设第二个元素为L,第三个为R- 在
L<R的情况下,我们用双指针不断逼近结果,找到所有可能性,具体细节请看下面代码
- 在
有了以上的思路我的代码实现如下
function threeSum(nums: number[]): number[][] {
const sorted = nums.sort((a, b) => a - b); // 排序
const len = nums.length;
const res = []
for (let i = 0; i < len; i++) {
if (sorted[i] > 0) break; // 如果第一个数都大于零,肯定没结果
if (i > 0 && sorted[i] === sorted[i - 1]) continue; // 如果和前面的重复了,去重。注意是i和i-1
// 下面是双指针来比较twoSum的做法
let L = i + 1;
let R = len - 1;
while (L < R) {
const sum = sorted[i] + sorted[L] + sorted[R];
if (sum === 0) {
res.push([sorted[i], sorted[L], sorted[R]])
// 注意下面两个while去重
while (L < R && sorted[L] === sorted[L + 1]) L++;
while (L < R && sorted[R] === sorted[R - 1]) R--;
L++
R--
continue;
}
if (sum < 0) L++
if (sum > 0) R--
}
}
return res;
};
时间复杂度
O(n^2): 数组排序O(nlogn), 遍历数组O(n), 双指针遍历O(n),整体为O(nlogn) + O(n) * O(n) = O(n^2)
这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。