算法题6:三数之和
题目描述:
给你一个整数数组 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 。
思路:
这个题我又没合格,只能想到三重循环,但是时间复杂度明显不可能满足要求,看了结题后我得总结是这样的:
1、首先想到的是三重循环,第一层循环确定a,第二层确定b,第三层确定c,然后想办法简单化,使循环层数减少
2、题目要求不能重复,那么为了不重复,有两个点可以帮助我们减少计算时间,首先可以把数组从小到大排序,这样可以保证小的在前面大的在后面便于判断,其次每重循环相邻两次循环的数不能相同否则会重复,如[-1,-1,-1,0,1,2]得到一个组合[-1,-1,0],第一层循环遍历到第二个数-1时就要跳过去,
否则还会得到[-1,-1,0]就重复了,因此每层循环可以减少循环此次,即相邻元素相同时则跳过
3、第三重循环可以改为和第二重循环并列的关系,通过双指针的方法,第一层循环固定一个数后(a、b、c中的左边的a),第二重循环和第三重循环可以一边从左右到右,另一边从有到左,像两个指针由两边ian同时往中间找b和c,c肯定比b大,当两个指针重合则进入下一次循环
python
class Solution: def threeSum(self, nums: List[int]) -> List[List[int]]: n=len(nums) res=[] nums.sort() for first in range(len(nums)): third = n - 1 # 右侧指针 if first > 0 and nums[first] == nums[first - 1]: # 和前一个一样则跳出,去掉重复项 continue for second in range(first + 1, n): if second > first + 1 and nums[second] == nums[second - 1]: # 如果和前面数一样则跳过 continue # 进行计算,如果nums[second] + nums[third] > -nums[first] 则有指针向左移动1 while (second < third and nums[second] + nums[third] > -nums[first]): third -= 1 if second == third: # 指针重合后退出 break if nums[second] + nums[third] == -nums[first]: res.append([nums[first], nums[second], nums[third]]) return res
结果:

java:
class Solution { public List<List<Integer>> threeSum(int[] nums) { int n = nums.length; Arrays.sort(nums); List<List<Integer>> res = new ArrayList<List<Integer>>(); for (int first = 0; first < n; ++first) { // 需要和上次枚举的数不同 if (first > 0 && nums[first] == nums[first - 1]) { continue; } // c对应的指针指向数据最右侧 int third = n - 1; for (int second = first + 1; second < n; ++second) { // 需和上次枚举的数不同 if (second > first + 1 && nums[second] == nums[second - 1]){ continue; } // 需保证b的指针在c指针的左侧 while (second < third && nums[second] + nums[third] > -nums[first]) { --third; } if (second == third) { break; } if (nums[second] + nums[third] == -nums[first]) { List<Integer> list = new ArrayList<Integer>(); list.add(nums[first]); list.add(nums[second]); list.add(nums[third]); res.add(list); } } } return res; } }
结果:



浙公网安备 33010602011771号