Medium!

题目描述:

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],满足要求的三元组集合为:
[[-1, 0, 1],[-1, -1, 2]
]

解题思路:

这道题让我们求三数之和,比之前那道Two Sum要复杂一些,考虑过先fix一个数,然后另外两个数使用Two Sum那种HashMap的解法,但是会有重复结果出现,就算使用set来去除重复也不行,会TLE,看来此题并不是考我们Two Sum的解法。那么我们来分析一下这道题的特点,要我们找出三个数且和为0,那么除了三个数全是0的情况之外,肯定会有负数和正数,我们还是要先fix一个数,然后去找另外两个数,我们只要找到两个数且和为第一个fix数的相反数就行了,既然另外两个数不能使用Two Sum的那种解法来找,如果能更有效的定位呢?我们肯定不希望遍历所有两个数的组合吧,所以如果数组是有序的,那么我们就可以用双指针以线性时间复杂度来遍历所有满足题意的两个数的组合。

我们对原数组进行排序,然后开始遍历排序后的数组,这里注意不是遍历到最后一个停止,而是遍历到倒数第三个就可以停止了。这里我们可以先做个剪枝优化,就是当遍历到正数的时候就break,为啥呢,因为我们的数组现在是有序的了,如果第一个要fix的数就是正数了,那么后面的数字就都是正数,就永远不会出现和为0的情况了。然后我们还要加上重复就跳过的处理,处理方法是从第二个数开始,如果和前面的数字相等,就跳过,因为我们不想把相同的数字fix两次。对于遍历到的数,用0减去这个fix的数得到一个target,然后只需要再找到两个数之和等于target即可。我们用两个指针分别指向fix数字之后开始的数组首尾两个数,如果两个数和正好为target,则将这两个数和fix的数一起存入结果中。然后就是跳过重复数字的步骤了,两个指针都需要检测重复数字。如果两数之和小于target,则我们将左边那个指针i右移一位,使得指向的数字增大一些。同理,如果两数之和大于target,则我们将右边那个指针j左移一位,使得指向的数字减小一些,代码如下:

C++参考答案一:

 1 class Solution {
 2 public:
 3     vector<vector<int>> threeSum(vector<int>& nums) {
 4         vector<vector<int>> res;
 5         sort(nums.begin(), nums.end());
 6         for (int k = 0; k < nums.size(); ++k) {
 7             if (nums[k] > 0) break;
 8             if (k > 0 && nums[k] == nums[k - 1]) continue;
 9             int target = 0 - nums[k];
10             int i = k + 1, j = nums.size() - 1;
11             while (i < j) {
12                 if (nums[i] + nums[j] == target) {
13                     res.push_back({nums[k], nums[i], nums[j]});
14                     while (i < j && nums[i] == nums[i + 1]) ++i;
15                     while (i < j && nums[j] == nums[j - 1]) --j;
16                     ++i; --j;
17                 } else if (nums[i] + nums[j] < target) ++i;
18                 else --j;
19             }
20         }
21         return res;
22     }
23 };

或者我们也可以利用set的不能包含重复项的特点来防止重复项的产生,那么我们就不需要检测数字是否被fix过两次,不过个人觉得还是前面那种解法更好一些,参见代码如下:

C++参考答案二:

 1 class Solution {
 2 public:
 3     vector<vector<int>> threeSum(vector<int>& nums) {
 4         set<vector<int>> res;
 5         sort(nums.begin(), nums.end());
 6         for (int k = 0; k < nums.size(); ++k) {
 7             if (nums[k] > 0) break;
 8             int target = 0 - nums[k];
 9             int i = k + 1, j = nums.size() - 1;
10             while (i < j) {
11                 if (nums[i] + nums[j] == target) {
12                     res.insert({nums[k], nums[i], nums[j]});
13                     while (i < j && nums[i] == nums[i + 1]) ++i;
14                     while (i < j && nums[j] == nums[j - 1]) --j;
15                     ++i; --j;
16                 } else if (nums[i] + nums[j] < target) ++i;
17                 else --j;
18             }
19         }
20         return vector<vector<int>>(res.begin(), res.end());
21     }
22 };

知识点补充:

C++中set的用法

set的特性是,所有元素都会根据元素的键值自动排序,set的元素不像map那样可以同时拥有实值(value)和键值(key),set元素的键值就是实值,实值就是键值。set不允许两个元素有相同的键值。使用的时候要包含头文件“#include<set>”。

set的各成员函数列表如下:

1. begin()--返回指向第一个元素的迭代器

2. clear()--清除所有元素

3. count()--返回某个值元素的个数

4. empty()--如果集合为空,返回true

5. end()--返回指向最后一个元素的迭代器

6. equal_range()--返回集合中与给定值相等的上下限的两个迭代器

7. erase()--删除集合中的元素

8. find()--返回一个指向被查找到元素的迭代器

9. get_allocator()--返回集合的分配器

10. insert()--在集合中插入元素

11. lower_bound()--返回指向大于(或等于)某值的第一个元素的迭代器

12. key_comp()--返回一个用于元素间值比较的函数

13. max_size()--返回集合能容纳的元素的最大限值

14. rbegin()--返回指向集合中最后一个元素的反向迭代器

15. rend()--返回指向集合中第一个元素的反向迭代器

16. size()--集合中元素的数目

17. swap()--交换两个集合变量

18. upper_bound()--返回大于某个值元素的迭代器

19. value_comp()--返回一个用于比较元素间的值的函数

 1 #include<set>
 2 #include<iostream>
 3 using namespace std;
 4 int main()
 5 {
 6     int i;
 7     int arr[5] = {0,1,2,3,4};
 8     set<int> iset(arr,arr+5);
 9
10     iset.insert(5);
11     cout<<"size:"<<iset.size()<<endl;
12     cout<<"3 count = "<<iset.count(3)<<endl;
13     iset.erase(1);
14
15     set<int>::iterator ite1 = iset.begin();
16     set<int>::iterator ite2 = iset.end();
17     for(;ite1!=ite2;ite1++)
18     {
19         cout<<*ite1;
20     }
21     cout<<endl;
22
23     ite1 = iset.find(3);
24     if(ite1!=iset.end())
25         cout<<"3 found"<<endl;
26
27     ite1 = iset.find(1);
28     if(ite1!=iset.end())
29         cout<<"1 not found"<<endl;
30 }

转载于:https://www.cnblogs.com/ariel-dreamland/p/9128122.html

LeetCode(15):三数之和相关推荐

  1. [双指针|模拟] leetcode 15 三数之和

    [双指针|模拟] leetcode 15 三数之和 1.题目 题目链接 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ? ...

  2. LeetCode 15. 三数之和(3Sum)

    15. 三数之和 15. 3Sum 题目描述 Given an array nums of n integers, are there elements a, b, c in nums such th ...

  3. Java实现 LeetCode 15 三数之和

    15. 三数之和 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以 ...

  4. LeetCode 15. 三数之和【双指针】

    15. 三数之和 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j.i != k 且 j != k ,同时还满足 nums[ ...

  5. LeetCode 15. 三数之和

    题目描述 15. 三数之和 思路 思路1 比较容易想到的就是,求三数之和等于0,可以等价于求两个数的和,然后看这个和的相反数是否在nums里面. 但是 T_T这样的话复杂度太高了,会超时,捂脸,最后三 ...

  6. LeetCode 15三数之和16最接近的三数之和

    三数之和(双指针) 题意: 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组. 注意 ...

  7. Leetcode 15.三数之和

    Time: 20190920 Type: Medium 题目描述 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所 ...

  8. Leetcode 15:三数之和(最详细解决方案!!!)

    给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 *a,b,c ,*使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. **注意:**答案中不可以包含重 ...

  9. 2021-5-11 Leetcode 15.三数之和

    1.1我的解法以及考虑到的几点问题 1)数组长度小于3的不用考虑,直接返回 2)暴力法:每一次查找不是自己选择的数字,看一下能否凑成零(但是这样不知道如何去重) 3)拆成一个数字+LC 1.两数之和的 ...

  10. Leetcode 15.三数之和 双指针 or 暴力哈希

    题目链接:传送门 题目:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组. 暴力+ ...

最新文章

  1. 智能哲学:“学习机器”与“机器学习” ——解读图灵思想中的人工智能
  2. 15个顶级Java多线程面试题及回答(高级java工程师)
  3. jQuery中的几个模块总结
  4. Java面试必备的集合源码详解,砥砺前行!
  5. Linux下配置OpenLDAP服务记录
  6. 举一反三:跨平台版本迁移之 XTTS 方案操作指南
  7. 传统输电线路巡检难?无人机这回立了大功!
  8. drools 7.x集成SparkStream 2.x
  9. android sudio jni 调用so_Android NDK-深入理解JNI
  10. 元素周期表排列的规律_元素周期表排列规律
  11. 知乎上(知乎上有一个完全错误的回答,下最好的正确评论)非常好的关于mAP,AP等目标检测参数的解释(原来之前我理解错了!!)
  12. 前端开发主流框架整理推荐
  13. 纹理(讲得比较详细的文章)
  14. mysql中column的用法_关于MySQL的一些用法
  15. 【技术】客服服务开发
  16. sublime text2配置文件详解(转)
  17. 标准模式(standard mode) 和 兼容模式(qurik mode)
  18. BLDC无刷直流电机驱动程序
  19. yana--Flutter一些学习
  20. 一学就会一用却废!到底应该用ETL还是ELT?

热门文章

  1. python和vba操作excel_python调用excel中VBA代码
  2. L2-003 月饼-团体程序设计天梯赛GPLT
  3. MYSQL专题-MySQL事务实现原理
  4. 电脑cmd命令大全_查询电脑IP地址
  5. 网工协议基础(1) OSI七层模型
  6. 云栖回顾|首届阿里云云原生生态合作伙伴大会:与伙伴能力融合,加速企业数字创新
  7. 怎么提升写代码的能力
  8. OpenYurt 入门 - 在树莓派上玩转 OpenYurt
  9. 课时 24:Kubernetes API 编程利器:Operator 和 Operator Framework(夙兴)
  10. 如何在graphpad表示出正负误差_GraphPad Prism 8.0绘制误差连线并填充颜色图