题目描述
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
首先讨论其简化版本两数之和的的情况
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
- for循环两遍遍历(c++代码)。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> b(2,-1);//用来承载结果,初始化一个大小为2,值为-1的容器b
for(int i=0;i<nums.size()-1;i++)
{
for(int j= i+1 ;j<nums.size();j++){
if(nums[i]+nums[j]==target){
b[0] = i;
b[1] = j;
break;
}
}
}
return b;
};
};
- 建立hash表,减小遍历层数(js代码,利用js数组的动态性建立hash,也可使用map)。
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
var res = new Array();
var hash = new Array();
for(var i = 0;i<nums.length;i++){
hash[nums[i]] = i;//建立hash表,将数组的值作为序号
}
for(i = 0;i<nums.length-1;i++){
if(hash[target-nums[i]]!=undefined&&i!=hash[target-nums[i]]){//在表中查找是否存在是否存在
res[0] = i;
res[1] = hash[target-nums[i]];
}
}
return res;
};
只遍历一遍,时间复杂度减小一个数量级。
因为不与自身比较,可以继续优化,在遍历时建hash表。
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
var res = new Array();
var hash = new Array();//优化,在遍历时建立hash表
for(i = 0;i<nums.length;i++){
if(hash[target-nums[i]]!=undefined){//在表中查找是否存在是否存在
res[0] = i;
res[1] = hash[target-nums[i]];
}
hash[nums[i]] = i;
}
return res;
};
三数之和解答
- 首先最笨的方法,采用for循环3层遍历。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
vector<int> temp(3);
for(int i = 0;i<nums.size()-2;i++){
for(int j = i+1;j<nums.size()-1;j++){
for(int k = j+1;k<nums.size();k++){
if(nums[i]+nums[j]+nums[k]==0){
temp[0] = nums[i];
temp[1] = nums[j];
temp[2] = nums[k];
res.push_back(temp);
}
}
}
}
return res;
}
};
这种办法时间复杂度最高,且由与原给定数组中数存在相同的元素,导致返回的数组中会出现大量重复的情况。
2. 同二数之和,可以建立hash表减少循环嵌套,同样存在。
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
var res = new Array();
var hash = new Array();
var j;
for( j = 0;j<nums.length;j++){
hash[nums[j]] = j;//建立hash
}
for(var i = 0;i<nums.length-2;i++){
for(j = i+1;j<nums.length-1;j++){
if(hash[-nums[i]-nums[j]]!=undefined&&hash[-nums[i]-nums[j]]>j){//检查hash是否存在,并确保与前两个数不同
var temp = new Array();//引用
temp[0] = nums[i];
temp[1] = nums[j];
temp[2] = -(nums[i]+nums[j]);
res.push(temp);
}
}
}
return res;
};
- 对于这种求固定和的问题,我们还可以先对数组进行排序,然后从两边进行查找,这样还可以解决重复的问题。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
vector<int> temp(3);
sort(nums.begin(),nums.end());//首先对nums进行排序
int i ,j, k;
if(nums.size()<3||nums[0]>0||nums[nums.size()-1]<0) return res;
for(i = 0 ;i<nums.size()-2;){
if(nums[i]>0) break;//最左值大于零排除
for(j = i+1,k = nums.size()-1;j<k;){
if(nums[i]+nums[j]+nums[k]==0){
temp[0] = nums[i];
temp[1] = nums[j];
temp[2] = nums[k];
res.push_back(temp);
do{
j++;
if(j>=k) break;
}while(nums[j]==nums[j-1]);
do{
k--;
if(j>=k) break;
if(nums[k]>0) break;
}while(nums[k]==nums[k+1]);
}else if(nums[i]+nums[j]+nums[k]>0){
do{
k--;
if(j>=k) break;
if(nums[k]>0) break;
}while(nums[k]==nums[k+1]);
}else{
do{
j++;
if(j>=k) break;
}while(nums[j]==nums[j-1]);
}
}
do{
i++;
if(i>=nums.size()-2) break;
}while(nums[i]==nums[i-1]);
}
return res;
}
};