题目描述
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。 注意: 答案中不可以包含重复的四元组。 示例: 给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。 满足要求的四元组集合为: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]
题解
最直接的想法当然是四重循环,暴力求解,复杂度为[latex] O(n^4) [/latex],直接拉进小黑屋。 因为做过二数之和,三数之和等题,想着能否题目转成已知的问题。因此下面的一个想法就诞生了,固定一个数a,然后问题转成求b + c + d = target - a三数之和的解,使用的方法是排序 + 双指针。然后再改变a找到所有解。
代码
时间复杂度为$o(n^3)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class Solution { public: vector<vector<int>> fourSum(vector<int>& nums, int target) { sort(nums.begin(), nums.end()); int len = nums.size(),beg, end, sum; vector<vector<int>>res; for(int i = 0; i < len - 3; ++i){ if(i > 0 && nums[i] == nums[i - 1]){ continue; } for(int j = i + 1; j < len - 2; ++j){ if(j > i + 1 && nums[j] == nums[j - 1]){ continue; } beg = j + 1, end = len - 1; while(beg < end){ sum = nums[i] + nums[j] + nums[beg] + nums[end]; if(sum > target){ --end; while(beg < end && nums[end] == nums[end + 1]){ --end; } } else if(sum < target){ ++beg; while(beg < end && nums[beg] == nums[beg - 1]){ ++beg; } } else{ res.push_back({nums[i], nums[j], nums[beg], nums[end]}); ++beg; while(beg < end && nums[beg] == nums[beg - 1]){ ++beg; } } } } } return res; } };
|
执行结果
优化
借助大佬的思路,加入两个if判断,用时瞬间超过90%! 1. 如果tmp = a + min{b + c + d}仍然大于target,则整个循环没有继续下去的必要了,后面的四数之和不小于tmp,即大于target。 2. 如果tmp = a + max{b + c + d}仍然小于target,则此趟循环可以continue。 具体见代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| class Solution { public: vector<vector<int>> fourSum(vector<int>& nums, int target) { sort(nums.begin(), nums.end()); int len = nums.size(),beg, end, sum; vector<vector<int>>res; for(int i = 0; i < len - 3; ++i){ if(i > 0 && nums[i] == nums[i - 1]){ continue; } if(nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target) break; if(nums[i] + nums[len-1] + nums[len-2] + nums[len-3] < target) continue; for(int j = i + 1; j < len - 2; ++j){ if(j > i + 1 && nums[j] == nums[j - 1]){ continue; } beg = j + 1, end = len - 1; while(beg < end){ sum = nums[i] + nums[j] + nums[beg] + nums[end]; if(sum > target){ --end; while(beg < end && nums[end] == nums[end + 1]){ --end; } } else if(sum < target){ ++beg; while(beg < end && nums[beg] == nums[beg - 1]){ ++beg; } } else{ res.push_back({nums[i], nums[j], nums[beg], nums[end]}); ++beg; while(beg < end && nums[beg] == nums[beg - 1]){ ++beg; } } } } } return res; } };
|
执行结果