力扣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] <= 105
令三元组为{a,b,c},其下标分别为i,j,k
1.为实现a+b+c=0三元组必然存在a<=b<=c(abc顺序未知),即可以先排序再遍历
2.遍历过程先定下a,把题目变换为b+c=-a的问题,这样可以使用双指针解决:
假设a<=b<=c成立,令b下标为left,c下标为right,可以有如下指针移动过程:
若nums[left]+nums[right]>goal,right--;
若nums[left]+nums[right]<goal,left++;
若nums[left]+nums[right]=goal,即找到一组
3.在遍历过程中,为了去重,需要在a和b的取值中去掉重复的值。
双指针
1 vector<vector<int>> threeSum(vector<int> &nums) 2 { 3 vector<vector<int>> result; 4 sort(nums.begin(), nums.end()); 5 for (int i = 0; i < nums.size(); ++i) 6 { 7 if (i > 0 && nums[i] == nums[i - 1]) 8 continue; 9 int left = i + 1, right = nums.size() - 1; 10 while (left < right) 11 { 12 int sum = nums[i] + nums[left] + nums[right]; 13 if (left > i + 1 && nums[left] == nums[left - 1]) 14 { 15 left++; 16 continue; 17 } 18 if (sum == 0) 19 { 20 result.push_back({nums[i], nums[left], nums[right]}); 21 left++; 22 } 23 else if (sum > 0) 24 { 25 right--; 26 } 27 else 28 { 29 left++; 30 } 31 } 32 } 33 return result; 34 } 35 };
优化后
1 class Solution { 2 public: 3 vector<vector<int>> threeSum(vector<int>& nums) { 4 vector<vector<int>> result; 5 set<vector<int>> filter; 6 sort(nums.begin(),nums.end()); 7 for (int i=0;i<nums.size();++i){ 8 if (i>0&&nums[i]==nums[i-1]) 9 continue; 10 //转换为二元组问题 11 int left=i+1,right=nums.size()-1; //双指针 12 int goal=-nums[i]; 13 for (;left<nums.size();++left){ 14 if (left>i+1&&nums[left]==nums[left-1]) //去重 15 continue; 16 while (left<right&&nums[left]+nums[right]>goal) //去重 17 { 18 right--; 19 } 20 if (left==right){ 21 break; 22 } 23 if (nums[left]+nums[right]==goal) 24 result.push_back({nums[i],nums[left],nums[right]}); 25 } 26 } 27 return result; 28 } 29 };
2.二分解法,依旧保证i < j < k的顺序去运算,便可去重
1 class Solution { 2 public: 3 vector<int> nums; 4 5 int binaryFind(int l, int r, int key) { 6 if (l > r) return -1; 7 int mid = (l + r) / 2; 8 if (nums[mid] == key) { 9 return mid; 10 } else if (nums[mid] > key) { 11 return binaryFind(l, mid - 1, key); 12 } else { 13 return binaryFind(mid + 1, r, key); 14 } 15 } 16 vector<vector<int>> threeSum(vector<int>& nums) { 17 vector<vector<int>> result; 18 sort(nums.begin(), nums.end()); 19 this -> nums = nums; 20 int len = nums.size(); 21 int lasti = INT32_MAX, lastj = INT32_MAX; 22 for (int i = 0; i < len; ++i) { 23 if (nums[i] == lasti){ 24 continue; 25 } 26 lasti = nums[i]; 27 for (int j = i + 1; j < len; ++j) { 28 if (nums[j] == lastj) { 29 continue; 30 } 31 lastj = nums[j]; 32 int k = binaryFind(j + 1, len - 1, -nums[i] - nums[j]); 33 if (k != -1) { 34 result.push_back({nums[i], nums[j], nums[k]}); 35 } 36 } 37 } 38 return result; 39 } 40 };
浙公网安备 33010602011771号