1 题目地址
15. 三数之和 - 力扣(LeetCode)15. 三数之和 - 给你一个整数数组 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 。 提示: * 3 <= nums.length <= 3000 * -105 <= nums[i] <= 105https://leetcode.cn/problems/3sum/description/
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 。提示:
3 <= nums.length <= 3000
-105 <= nums[i] <= 105
3 解题思路
方式一:暴力破解法:三层循环,判断nums[i]+nums[j]+nums[k]=0,则记录下来;去重:将nums[i]+nums[j]+nums[k]=0的三个数据排序后生成都逗号分隔的字符串放到set集合中,重复则不记录到返回结果中,不重复则记录。
方式二:双指针法
1、首先给原数组排序,从小到大 (可以根据相加大于 小于 等于0结果判断如何移动)
2、定义初始指针i(索引为0), left(指针i+1位置), right(指针nums.length-1位置)
3、判断三个值相加的结果,决定如何移动
3.1、nums[i]>0:结束,最小值都小于0,所以不会存在三者相加等于0
3.2、nums[i]+nums[left]+nums[right]>0:right--,使三者相加的值变小
3.3、nums[i]+nums[left]+nums[right]<0:left++,使三者相加的值变大
3.4、nums[i]+nums[left]+nums[right]=0:记录结果集合,left++,right-- 保证left<right
4、去重,答案中不能包含相同的三元素,三个指针都要考虑去重( i left right)
4.1、nums[i]=nums[i+1],不能这样去重不能有重复的三元组,但三元组内的元素是可以重复的
4.2、nums[i]=nums[i-1],此时需要去重,因为nums[i]已经将与nums[left]、nums[right]相加等于0结果记录下来了
4.3、同理left、right相同的操作;
nums[left]=nums[left-1], 则left++
nums[right]=nums[right+1], 则right--;right只从最右侧,向左移动的,所以去重方向跟left是
相反的

4 代码编写
4.1 暴力方式
三层循环,报超时
class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> resultList = new ArrayList<>();Set<String> hashSet = new HashSet<>();for (int i=0; i<nums.length-2; i++) {for (int j=i+1; j<nums.length-1; j++) {for (int k = j + 1; k < nums.length; k++) {if (nums[i] + nums[j] + nums[k] == 0) {List<Integer> itemList = Arrays.asList(nums[i], nums[j], nums[k]);Collections.sort(itemList);String join = toStr(itemList);if (!hashSet.contains(join)) {hashSet.add(join);resultList.add(itemList);}}}}}return resultList;} public String toStr(List<Integer> itemList) {String a = "";for (int i=0; i<itemList.size(); i++) {a += itemList.get(i) + "-";}return a;}
}

4.2 双指针法
class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> resultList = new ArrayList<>();for (int i=0; i<nums.length; i++) {// 最小值大于0,则不会存在三数之和等于0的情况if (nums[i]>0) {return resultList;}// 去重逻辑,继续向右移动if (i>=1 && nums[i]==nums[i-1]) {continue;}int left = i + 1;int right = nums.length - 1;while (left<right) {int result = nums[i] + nums[left] + nums[right];if (result==0) {List<Integer> itemList = new ArrayList<>();itemList.add(nums[i]);itemList.add(nums[left]);itemList.add(nums[right]);resultList.add(itemList);// 去重逻辑,对b 和 c去重while (right > left && nums[right] == nums[right - 1]) right--;while (right > left && nums[left] == nums[left + 1]) left++;left++;right--;} else if (result>0) {right--;} else {left++;}}}return resultList;}
}