LeetCode(15):三数之和
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++参考答案一:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
for (int k = ; k < nums.size(); ++k) {
if (nums[k] > ) break;
if (k > && nums[k] == nums[k - ]) continue;
int target = - nums[k];
int i = k + , j = nums.size() - ;
while (i < j) {
if (nums[i] + nums[j] == target) {
res.push_back({nums[k], nums[i], nums[j]});
while (i < j && nums[i] == nums[i + ]) ++i;
while (i < j && nums[j] == nums[j - ]) --j;
++i; --j;
} else if (nums[i] + nums[j] < target) ++i;
else --j;
}
}
return res;
}
};
或者我们也可以利用set的不能包含重复项的特点来防止重复项的产生,那么我们就不需要检测数字是否被fix过两次,不过个人觉得还是前面那种解法更好一些,参见代码如下:
C++参考答案二:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
set<vector<int>> res;
sort(nums.begin(), nums.end());
for (int k = ; k < nums.size(); ++k) {
if (nums[k] > ) break;
int target = - nums[k];
int i = k + , j = nums.size() - ;
while (i < j) {
if (nums[i] + nums[j] == target) {
res.insert({nums[k], nums[i], nums[j]});
while (i < j && nums[i] == nums[i + ]) ++i;
while (i < j && nums[j] == nums[j - ]) --j;
++i; --j;
} else if (nums[i] + nums[j] < target) ++i;
else --j;
}
}
return vector<vector<int>>(res.begin(), res.end());
}
};
知识点补充:
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()--返回一个用于比较元素间的值的函数
#include<set>
#include<iostream>
using namespace std;
int main()
{
int i;
int arr[] = {,,,,};
set<int> iset(arr,arr+); iset.insert();
cout<<"size:"<<iset.size()<<endl;
cout<<"3 count = "<<iset.count()<<endl;
iset.erase(); set<int>::iterator ite1 = iset.begin();
set<int>::iterator ite2 = iset.end();
for(;ite1!=ite2;ite1++)
{
cout<<*ite1;
}
cout<<endl; ite1 = iset.find();
if(ite1!=iset.end())
cout<<"3 found"<<endl; ite1 = iset.find();
if(ite1!=iset.end())
cout<<"1 not found"<<endl;
}
LeetCode(15):三数之和的更多相关文章
- LeetCode 15. 三数之和(3Sum)
15. 三数之和 15. 3Sum 题目描述 Given an array nums of n integers, are there elements a, b, c in nums such th ...
- Java实现 LeetCode 15 三数之和
15. 三数之和 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以 ...
- LeetCode——15. 三数之和
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复的三元组. ...
- LeetCode 15. 三数之和(3Sum)
题目描述 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复 ...
- [Leetcode 15]三数之和 3 Sum
[题目] Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? ...
- [LeetCode]15. 三数之和(数组)(双指针)
题目 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复的三 ...
- [LeetCode] 15. 三数之和
题目链接:https://leetcode-cn.com/problems/3sum/ 题目描述: 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a ...
- LeetCode:三数之和【15】
LeetCode:三数之和[15] 题目描述 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的 ...
- 代码随想录第七天| 454.四数相加II、383. 赎金信 、15. 三数之和 、18. 四数之和
第一题454.四数相加II 给你四个整数数组 nums1.nums2.nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足: 0 <= i, ...
- leetcode题目15.三数之和(中等)
题目描述: 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重 ...
随机推荐
- SQL 中LTrim、RTrim与Trim的用法
LTrim.RTrim与 Trim 函数 返回 Variant (String),其中包含指定字符串的拷贝,没有前导空白 (LTrim).尾随空白 (RTrim) 或前导和尾随空白 (Trim).语法 ...
- suoi31 最近公共祖先2 (倍增lca)
根为r时x.y的公共祖先,就是lca(x,r),lca(x,y),lca(r,y)中深度最大的那一个,不要再在倍增的时候判来判去还判不对了... #include<bits/stdc++.h&g ...
- WEB入门之十一 JS面向对象
学习内容 JavaScript类的定义模式 JavaScript继承的实现 JavaScript抽象类 JavaScript解析XML 能力目标 深入了解JavaScript类的定义模式 理解Java ...
- 【转】METADATATYPE的使用,MVC的MODEL层数据验证
http://www.cnblogs.com/chshnan/archive/2011/07/08/2100713.html MetadataType的使用,MVC的Model层数据验证指定要与数据模 ...
- VirtualBox安装Centos后实现文件夹共享
不同虚拟机中的系统和windows之间实现文件共享方式也不一样,在VMWare虚拟机请参考链接:http://www.cnblogs.com/vincentfu/p/5402666.html 进入主题 ...
- eos源码剖析之controller
controller::block_status,区块状态枚举类,包括: irreversible = 0,该区块已经被当前节点应用,并且被认为是不可逆的.validated = 1,这是由一个有效生 ...
- Helm一:简介
目录 什么是Helm Helm解决的问题 Helm原理 Helm架构 Helm功能 Helm三个重要概念 Helm组件 Helm Client Tiller Server Helm实现 什么是Helm ...
- 关闭ubuntu dash 方法
因为ubuntu默认的sh是连接到dash的,又因为dash跟bash的不兼容所以出错了.执行时可以把sh换成bash 文件名.sh来执行.成功.dash是什么东西,查了一下,应该也是一种shell, ...
- Scala进阶之路-高级数据类型之集合的使用
Scala进阶之路-高级数据类型之集合的使用 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala 的集合有三大类:序列 Seq.集 Set.映射 Map,所有的集合都扩展自 ...
- POJ-1459 Power Network(最大流)
https://vjudge.net/problem/POJ-1459 题解转载自:優YoU http://user.qzone.qq.com/289065406/blog/1299339754 解题 ...