Leetcode 15. 三数之和
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情。
❤️欢迎订阅java厂长《LeetCode每日一题》 ❤️
1、题目📑
给你一个包含 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]]
实例2:
输入:nums = []
输出:[]
实例3:
输入:nums = [0]
输出:[]
提示:
0 <= nums.length <= 3000-105 <= nums[i] <= 105
2、思路🧠
方法一:暴力
- 暴力的时间复杂度为 O(N3) ,但是可通过双指针动态消除掉无效解。
方法二:排序 ➕ 双指针
本题的难点在于如何消除重复解,以提高效率。
- 特判:如果数组的为
null或者 长度 < 3,直接返回空集合。 - 初始化:
- 对数组先进行排序,排序后出现固定位置的数字大于0,则后面的数字不用进行考虑,直接结束
- 确定固定指针
k,定义双指针i,j - 求和结果
sum,sum = nums[i] + nums[j] + nums[k];
- 循环遍历:
- 若
num[k] > 0:因为已经排序,所以后面不可能出现三个数相加和等于 0 的情况,直接结束。 - 重复元素:出现相同的元素,跳过
- 当
L<R时,执行循环:- 若和大于 0
sum > 0,则说明 nums[j] 太大,j 左移 - 若和小于 0
sum < 0,则说明 nums[i] 太小,i 右移 - 若和等于 0
sum == 0,执行循环,去判断左和右数字是否与下一位置重复,目的是去除重复解。并同时将i,j移到下一位置,寻找新的解
- 若和大于 0
- 若
- 返回结果
res
废话少说~~~~~上代码!
3、代码👨💻
第一次commit AC
public static List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
for (int k = 0; k < nums.length - 2; k++) { //固定其中一个指针
if(nums[k] > 0) break; //排序后,第K个位置的数字大于0,则K位置之后的数字都大于0
if (k > 0 && nums[k] == nums[k - 1]) continue; //当前k位置的元素与前一个位置元素相同则不用在进行查找
int i = k + 1, j = nums.length - 1;
while(i < j) {
int sum = nums[i] + nums[j] + nums[k];
if (sum < 0) {
i+=1;
}else if(sum > 0) {
j-=1;
}else {
res.add(Arrays.asList(nums[k], nums[i], nums[j]));
while(i < j && nums[i] == nums[i + 1]) i+=1; //当前i位置的元素与前一个位置元素相同则不用在进行查找
while(i < j && nums[j] == nums[j - 1]) j-=1; //当前j位置的元素与前一个位置元素相同则不用在进行查找
i+=1;
j-=1;
}
}
}
return res;
}
时间复杂度:O(N2),数组排序 O(NlogN),遍历数组 O(N),双指针遍历 O(N),总体 O(NlogN) ➕ O(N) ✖ O(N) 💨 O(N2)
空间复杂度:O(1)
4、总结
该题目的对重复解的去重进行考察和练习,同时对于数组要有排序的敏感度,对双指针的解法也要非常的熟悉,并且能够想到具体问题具体解决。
❤️来自专栏《LeetCode基础算法题》欢迎订阅❤️
厂长写博客目的初衷很简单,希望大家在学习的过程中少走弯路,多学一些东西,对自己有帮助的留下你的赞赞👍或者关注➕都是对我最大的支持,你的关注和点赞给厂长每天更文的动力。
对文章其中一部分不理解,都可以评论区回复我,我们来一起讨论,共同学习,一起进步!