当你初学C++时VS大佬眼中的C++
问题描述
给定一个包含 n
个整数的数组 S
,判断是否存在三个元素 a
, b
, c
,使得 a + b + c = 0
?找出所有满足条件的三元组,且这些三元组中的元素必须按非降序排列(即 a ≤ b ≤ c
),并且解集中不能包含重复的三元组。
示例:
输入:S = [-10, 0, 10, 20, -10, -40]
输出:[[-10, -10, 20], [-10, 0, 10]]
初学时:双重遍历,先求两个数字之和,第三个数字缺什么找什么。我记得有个find函数。找到了!
什么还要排序?
创建一个新的函数,我真聪明!
// 其实到这一步我已经后悔了,我想重头再来的
什么还不能重复,b事真多!
不应该啊
怎么会不全呢
原来如此
再加两个函数
为什么显示栈溢出呢
逻辑上没问题啊
难道是这个地方出问题了
再来个函数
快晕了,不过我竟然能写这么多函数还能调用成功,真厉害
快了,快了,运行到第11/20个案例了
怎么会呢,明明可以运行
哪个啥鸟函数给我把数组顺序打乱了
终于
<-<-<-
两小时后~
<-<-<-
终于
终于成功了
大佬眼中:
排序,循环枚举,指针查重
,秒了。(三分钟)
解题思路
1. 暴力解法
最直观的解法是使用三重循环枚举所有可能的三元组,然后判断它们的和是否为零。这种方法的时间复杂度为 O(n^3)
,在 n
较大时(如 n = 1000
)会非常慢,无法在合理时间内得到结果。
2. 排序 + 双指针优化
为了优化时间复杂度,我们可以先对数组进行排序,然后使用双指针技巧来减少不必要的枚举。
步骤如下:
- 排序:首先对数组进行排序,这样我们可以利用有序性来减少枚举的次数。
- 枚举第一个数:使用一个循环枚举第一个数
num[i]
,然后在剩下的数组中使用双指针寻找另外两个数num[l]
和num[r]
,使得num[i] + num[l] + num[r] = 0
。 - 双指针:初始化左指针
l = i + 1
,右指针r = n - 1
。根据当前三数之和与零的关系,移动指针:- 如果和大于零,说明右指针的数太大,需要将右指针左移。
- 如果和小于零,说明左指针的数太小,需要将左指针右移。
- 如果和等于零,找到一个有效的三元组,记录下来,并移动指针以避免重复。
- 去重:在枚举第一个数和移动指针时,跳过重复的元素,以避免重复的三元组。
时间复杂度:排序的时间复杂度为 O(n log n)
,双指针部分的时间复杂度为 O(n^2)
,因此总的时间复杂度为 O(n^2)
。
空间复杂度:除了存储结果的数组外,只使用了常数级别的额外空间,因此空间复杂度为 O(1)
。
代码实现
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& num) {
vector<vector<int>> ans;
sort(num.begin(), num.end()); // 先对数组进行排序
for (int i = 0; i + 2 < num.size(); i++) {
int l = i + 1, r = num.size() - 1;
while (l < r) {
while (l < r && num[i] + num[l] + num[r] > 0) r--; // 和大于零,右指针左移
if (l == r) break; // 指针相遇,退出循环
if (num[i] + num[l] + num[r] == 0) {
ans.push_back(vector<int>{num[i], num[l], num[r]}); // 找到一个有效的三元组
while (l < r && num[l + 1] == num[l]) l++; // 跳过重复的左指针元素
}
l++; // 左指针右移
}
while (i + 1 < num.size() && num[i + 1] == num[i]) i++; // 跳过重复的第一个数
}
return ans;
}
};
代码解析
- 排序:首先对数组进行排序,使得我们可以利用有序性来减少枚举的次数。
- 枚举第一个数:使用
for
循环枚举第一个数num[i]
,并在循环中跳过重复的元素。 - 双指针:在每次枚举第一个数后,初始化左指针
l = i + 1
和右指针r = num.size() - 1
,然后根据三数之和与零的关系移动指针。 - 去重:在找到有效的三元组后,跳过重复的左指针元素,并在枚举第一个数时跳过重复的元素。
附上铁头代码——主打我就不信行不通
#include <algorithm>
#include <cstdio>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param num int整型vector
* @return int整型vector<vector<>>
*/
vector<vector<int> > threeSum(vector<int>& num) {
// write code here
int n = num.size();
int m=0;
vector<vector<int> > result;
for(int i=0; i<n; i++){
for(int j=i+1; j<n; j++){
int obj = 0 - num[i] -num[j];
int z = findNumber(num, obj,j);
if(obj ==4){
cout << num[i] << num[j] <<num[z] <<endl;
}
if(z > 0 ){
bool AAA = moto(result,num[i],num[j],num[z]);
int opc =num[i]; // 此时已经麻木了
int ua =num[j];
int can =num[z];
sortThreeDescending(opc,ua,can);
// cout << num[i] << num[j] <<num[z] <<endl;
if(!AAA){
int pos = position(result, opc,ua,can);
// cout << pos << num[i] << num[j] <<num[z] <<endl;
auto p = result.begin() + pos;
result.insert(p,{opc,ua,can});
}
}
}
}
return result;
}
int findNumber(const std::vector<int>& arr, int target, int j) {
for (int i = 0; i < arr.size(); i++) {
if (arr[i] == target && i > j) {
return i; // 返回目标值的位置
}
}
return -1; // 如果未找到,返回 -1
}
bool moto(vector<vector<int> >& result, int i, int j, int z) {
int m = result.size();
for (int a = 0; a < m; a++) {
// 检查当前三元组是否包含i, j, z
bool contains_i = false, contains_j = false, contains_z = false;
for (int b = 0; b < 3; b++) {
if (result[a][b] == i && contains_i == false) {contains_i = true;}
else if (result[a][b] == j && contains_j == false) {contains_j = true;}
else if (result[a][b] == z && contains_z == false) {contains_z = true;}
}
// 如果三个数都在当前三元组中,返回true
if (contains_i && contains_j && contains_z) {
return true;
}
}
// 未找到匹配的三元组,返回false
return false;
}
void sortThreeDescending(int& a, int& b, int& c) {
if (a > b) std::swap(a, b);
if (a > c) std::swap(a, c);
if (b > c) std::swap(b, c);
}
int position(vector<vector<int> >& result, int i, int j, int z){
int m = result.size();
int pos = 0;
for (int a = 0; a < m; a++){
if( i > result[a][0] ){
pos = a+1;
}
else if(i == result[a][0])
{
if( j > result[a][1] ){
pos = a+1;
}
else if( j == result[a][1]){
if(z > result[a][2]){ pos = a+1; }
else{ return a; }
}
else{
return a;
}
}
else{
return pos;
}
}
return pos;
if(m ==0){
return 0;
}
}
};
我就说能行!!!!
点个赞吧