一、题目
15. 三数之和
16. 最接近的三数之和
18. 四数之和
二、分析
- 这个题与两数之和类似,可以采用双指针法,但是需要先排序。这样快排的时间复杂度是
O
(
n
⋅
l
o
g
n
)
O(n·logn)
O(n⋅logn),遍历第一个数时间复杂度为
O
(
n
)
O(n)
O(n),双指针找两数和问题时间复杂度为
O
(
n
)
O(n)
O(n),所以总体的时间复杂度是
O
(
n
2
+
n
⋅
l
o
n
g
n
)
=
O
(
n
2
)
O(n^2+n·longn)=O(n^2)
O(n2+n⋅longn)=O(n2)。没有用到额外的辅助数组,所以空间复杂度是
O
(
1
)
O(1)
O(1)。
关键是如何去重:
例如:-5 -3 -2 -1 0 0 0 1 1 1 3 3 4 4 4
对于-5来说,要找两个数与其和为0;
当left移动到第一个1,right在最后一个4时,满足条件。
接下来的left和right和上一步的完全相等,所以一定是重复答案。直接跳过
- 将判断条件换了就可以,如果大于target,right就往左移,反之left往右移动,移动结束的时候就是离target最近的时候。
- 四数之和
直接套用三数之和做。
也可以改为3个指针移动!
三、代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n(nums.size());
if(n < 3) return vector<vector<int>>();
vector<vector<int>> res;
sort(nums, 0, n-1);
int left(0), right(0);
for(int i = 0; i < n-2; i ++){
if(i>0 && nums[i-1] == nums[i]) continue;
left = i+1;
right = n-1;
while(left < right){
//去重
if(left>i+1 && right < n-1 && nums[left] == nums[left-1] && nums[right] == nums[right+1]){
left++;
right --;
continue;
}
//满足条件,加入到结果集
if(nums[i] + nums[left] + nums[right] == 0){
vector<int> temp(3);
temp[0] = nums[i];
temp[1] = nums[left];
temp[2] = nums[right];
res.push_back(temp);
right --;
left ++;
}else if(nums[i] + nums[left] + nums[right] > 0){
//大于0说明右侧的数太大,左移减小之
right --;
}else{
left ++;
}
}
}
return res;
}
//快排
void sort(vector<int> &nums, int low, int high){
if(low < high){
int X(nums[low]), i(low), j(high);
while(i < j){
while(i < j && nums[j] >= X) j --;
if(i < j) nums[i++] = nums[j];
while(i < j && nums[i] <= X) i ++;
if(i < j) nums[j--] = nums[i];
}
nums[i] = X;
sort(nums, low, i -1);
sort(nums, i+1, high);
}
}
};
执行用时:176 ms, 在所有 C++ 提交中击败了14.36的用户
内存消耗:20.8 MB, 在所有 C++ 提交中击败了21.31%的用户
为什么我的算法执行时间如此之长!
- 最接近的三数之和
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
int n(nums.size());
int res = nums[0] + nums[1] + nums[2];
sort(nums, 0, n-1);
int left(0), right(0);
for(int i = 0; i < n-2; i ++){
if(i>0 && nums[i-1] == nums[i]) continue;
left = i+1;
right = n-1;
while(left < right){
if(left>i+1 && right < n-1 && nums[left] == nums[left-1] && nums[right] == nums[right+1]){
left++;
right --;
continue;
}
// 只改了这里这一部分,每次记录新的结果
int mius = nums[i] + nums[left] + nums[right];
if(abs(target - res) > abs(mius - target))
res = nums[i] + nums[left] + nums[right];
if(mius > target){
// 同时也改了判断条件
right --;
}else{
left ++;
}
}
}
return res;
}
void sort(vector<int> &nums, int low, int high){
if(low < high){
int X(nums[low]), i(low), j(high);
while(i < j){
while(i < j && nums[j] >= X) j --;
if(i < j) nums[i++] = nums[j];
while(i < j && nums[i] <= X) i ++;
if(i < j) nums[j--] = nums[i];
}
nums[i] = X;
sort(nums, low, i -1);
sort(nums, i+1, high);
}
}
};
执行用时:20 ms, 在所有 C++ 提交中击败了37.11%的用户
内存消耗:9.6 MB, 在所有 C++ 提交中击败了74.84%的用户
- 四数之和
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
int n(nums.size());
if(n < 4) return vector<vector<int>>();
sort(nums, 0, n-1);
vector<vector<int>> res;
for(int i = 0; i < n; i ++){
if(i>0 && nums[i-1] == nums[i]) continue;
vector<vector<int>> temp = threeSum(nums, i+1, target-nums[i]);
for(int j = 0;j < temp.size(); j++){
vector<int> aaa(4);
aaa[0] = nums[i];
aaa[1] = temp[j][0];
aaa[2] = temp[j][1];
aaa[3] = temp[j][2];
res.push_back(aaa);
}
}
return res;
}
vector<vector<int>> threeSum(vector<int>& nums, int start, int target) {
int n(nums.size());
if(n < 3) return vector<vector<int>>();
vector<vector<int>> res;
int left(start), right(start);
for(int i = start; i < n-2; i ++){
if(i>start && nums[i-1] == nums[i]) continue;
left = i+1;
right = n-1;
while(left < right){
if(left>i+1 && right < n-1 && nums[left] == nums[left-1] && nums[right] == nums[right+1]){
left++;
right --;
continue;
}
if(nums[i] + nums[left] + nums[right] == target){
vector<int> temp(3);
temp[0] = nums[i];
temp[1] = nums[left];
temp[2] = nums[right];
res.push_back(temp);
right --;
left ++;
}else if(nums[i] + nums[left] + nums[right] > target){
right --;
}else{
left ++;
}
}
}
return res;
}
void sort(vector<int> &nums, int low, int high){
if(low < high){
int X(nums[low]), i(low), j(high);
while(i < j){
while(i < j && nums[j] >= X) j --;
if(i < j) nums[i++] = nums[j];
while(i < j && nums[i] <= X) i ++;
if(i < j) nums[j--] = nums[i];
}
nums[i] = X;
sort(nums, low, i -1);
sort(nums, i+1, high);
}
}
};
执行用时:124 ms, 在所有 C++ 提交中击败了34.79%的用户
内存消耗:12.8 MB, 在所有 C++ 提交中击败了38.69%的用户