题目描述
三数之和
代码解析
暴力
在做这一道题的时候,脑海里先想出来的是暴力方法,一次排序,将这个数组变为有序的,再通过三次for循环来寻找满足条件的数字,然后将符合条件的数组与之前符合条件的数组进行一一对比,来完成去重的目的,时间复杂度光是三层for循环就达到了n^3,再加上一个sort和count函数,nlogn + mn^3。
class Solution {
public:bool chech(int a, int b, int c){return a + b + c == 0;}vector<vector<int>> threeSum(vector<int>& na) {vector<vector<int>> ans;int n = na.size();sort(na.begin(), na.end());for (int i = 0; i < n; i++){for (int j = i + 1; j < n; j++){for (int k = j + 1; k < n; k++){if (chech(na[i], na[k], na[j])){vector<int> a(3, 0);a[0] = na[i];a[1] = na[j];a[2] = na[k];if (count(ans.begin(), ans.end(), a) == 0)ans.push_back(a);}}}}return ans;}
};
优化
这个时候要想代码如何进行优化,如何把判重的count和后两层循环给优化了,这样就能把时间复杂度从nlogn + mn^3降低到nlogn + n^2。
要找一个满足条件的三个数,我们可以先固定一个数字,然后就可以只考虑除固定数字之外的区间了,在另一个区间可以找两个指针l和r,如果说l指针指向的数字+r指针指向的数字,等于 事前固定的数字的相反数,就可以达到题目要求了。
如果说l+r > -i,说明r太大,r--;或者说是r + l > -i,说明l太小,l++。当l和r相交的时候依旧没有找到答案,就说明i在某个固定的位置是没有解的,将i++,即可。然后继续在l和r区间寻找符合题意的数字。
题目要求不能有重复的,什么情况下会出现重读的?当l + r == -i的时候,l的下一位或者r的上一位跟l或r本身是相同的,就说明出现了重复的情况,也有可能是i跟i的下一位相同。所以可以以此为条件,来进行去重。也可以将所有符合题意的答案都加入到一个数组当中,然后使用去重算法,也可以达到去重的目的。
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {int n = nums.size();sort(nums.begin(), nums.end());vector<vector<int>> res;for (int i = 0; i < n;){if (nums[i] > 0) break;int l = i + 1, r = n - 1;int t = -nums[i];while (l < r){int sum = nums[l] + nums[r];if (sum > t) r--;else if (sum < t) l++;else {res.push_back({nums[l], nums[r], nums[i]});l++, r--;while (l < r && nums[l] == nums[l - 1]){l++;}while (l < r && nums[r] == nums[r + 1]) {r--;}}}i++;while (i < n && nums[i] == nums[i - 1]) i++;}return res;}
};
扩展
四数之和
四数之和和三数之和的代码类似,可以当练习做一下。
class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {int n = nums.size();vector<vector<int>> res;sort(nums.begin(), nums.end());for (int i = 0; i < n ; ){for (int j = i + 1; j < n; ){int l = j + 1;int r = n - 1;long long tmp = nums[i] + nums[j];long long t = target - tmp;while (l < r){if ((long long)(nums[l] + nums[r]) > t) r--;else if ((long long)(nums[l] + nums[r]) < t) l++;else {res.push_back({nums[i], nums[j], nums[l], nums[r]});l++;r--;while (l < r && nums[l] == nums[l - 1]){l++;}while (l < r && nums[r] == nums[r + 1]) {r--;}}}j++;while (j < n && nums[j] == nums[j - 1]) j++;}i++;while (i < n && nums[i] == nums[i - 1]) i++;}return res;}
};