您的位置:首页 > 其它

leetcode 15 3Sum

2015-08-27 13:39 567 查看
3Sum

Total Accepted: 70783 Total Submissions: 419673

Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)

The solution set must not contain duplicate triplets.

For example, given array S = {-1 0 1 2 -1 -4},

A solution set is:

(-1, 0, 1)

(-1, -1, 2)

这道题是之前的第一题2Sum的升级版,除了要求找出所有可能的符合的3元组之外,还要以非降序输出。下面就结合代码来解释:

int** threeSum(int* nums, int numsSize, int* returnSize)
{
if(numsSize == 0)
return NULL;
int min_element = 100000000;
int max_element = -100000000;
for(int i = 0; i < numsSize; i++)
{
if(min_element > nums[i])
min_element = nums[i];
if(max_element < nums[i])
max_element = nums[i];
}

int offset = -1* min_element;


函数一开始先判断是空的情况,如果是空则返回NULL。然后找出整个输入数据中的最大值和最小值,这样的目的是为了确定hash表的长度以及偏移量offset的值。偏移量等于最小元素值的相反数,这样的目的是为了通过offset使得min_element对应于hash表的第一个位置。

int *hashTable = (int*)malloc(sizeof(int)*(max_element - min_element + 1));

memset(hashTable, 0, sizeof(int) * (max_element - min_element + 1));
for(int i = 0; i < numsSize; i++)
{
hashTable[nums[i] + offset]++;
}


确定了大小,下一步就是生成这张hash表,然后用memset函数把hash表全部置为0,然后循环为每个输入的数找到对应的hash表的位置,然后将对应的hash表的值加1.

int **result = (int**)malloc(sizeof(int*) * 300);
*returnSize = 0;
for(int i = 0; i < numsSize; i++)
{
int target = -1 * nums[i];
int *newHashTable = (int*)malloc(sizeof(int) * (max_element - min_element + 1));
memcpy(newHashTable, hashTable, sizeof(int) * (max_element - min_element + 1));
if(newHashTable[nums[i] + offset] > 0)
newHashTable[nums[i] + offset]--;
else if(newHashTable[nums[i] + offset] == 0)
continue;
twoSum(nums, numsSize, returnSize, newHashTable, max_element - min_element + 1, target, i+1, offset, result, nums[i]);
hashTable[nums[i] + offset] = 0;

}

return result;
}


首先开一个存储结果的二维数组,这个地方我设的值是300,也就是说最多支持300种三维组,当然如果册数数据很大,那么很可能结果会多于300种,但就这道题而言300够用了。然后我们进入到循环之中,按顺序取数组中每一个数,由于要求相加的结果为0,所以我们的目标target就是剩下的两个数的相加之和是第一个数的相反数,然我们复制当前的hash表,原因是在每次进入twoSum之前,hash表都会做特定的修改,而这个修改只在这一次迭代中起作用,下次迭代时我们可能并不需要这个修改,要使用原本的hash表。因此每次迭代我们都将原本的hash表复制一张,然后然后复制的hash表仅用于这一次的迭代。

产生了新的hash表之后,我们当前的这个值在hash表中的值,如果大于0,说明这个值存在于输入中,因此我们使用了当前值之后,当前值对应的数量就会减少1. 如果当前值对应的hash表中的值为0,说明这个值已经不能再使用了(有可能是当前值出现了多次,之前已经使用过当前值作第一个值了,所有可能的组合都找出来了),所以直接跳过进入下一次的迭代。

之后我们就可以进入twoSum函数,即找出两个值,它们之和为target,当twoSum函数返回后,把当前值置为0,因为所有使用当前值作为第一个值得情况我们已经都找出来了,如果之后又碰到当前值做第一个值,那我们就可以直接跳过了。

void twoSum(int* nums, int numsSize, int* returnSize, int *hashTable, int hTlen, int target, int start, int offset, int**result, int current)
{
int NeedValue;

int count = *returnSize;
for(int i = start; i < numsSize; i++)
{
if(!hashTable[nums[i]+offset])
continue;
hashTable[nums[i]+offset]--;
NeedValue = target - nums[i];
if(NeedValue + offset < 0 || NeedValue + offset > hTlen - 1)
{
hashTable[nums[i]+offset] = 0;
continue;
}


Two sum这个函数是我们的核心,首先定义NeedValue, 它不同于target,它等于target减去第二个数,也就是说它是我们想要的第三个数的值。然后我们从第一个数的下一个位置开始做为第二个数,这样保证了,第二个数b始终在第一个数a的后面,这样就避免了和之前搜索结果重复的情况,同样第三个数c一定在第二个数b后面,否则,我们就会在搜索到b之前,先搜索到第三个数c,之后我们就会找到b作为第三个数,找到这个组合后,我们会把b,c对应的hash表都置为0,因此在遇到b时直接跳过,不会搜索。而我们现在在搜索b,就说明第三个数c一定在b后面,同时b一定在a后面。 在循环中,我们首先查看当前正在搜索的值对应的hash值,如果为0,那么这个值
4000
不可用,直接跳过,找下一个搜索值。否则对应的hash值减1,我们采用当前搜索值作为第二个数,所以剩下的具有这个值的可用的数少了一个。在确定第二个值之后我们,就可以确定我们需要的第三个值了,如果我们想要的第三个值对应的索引值不在hash表范围内,那么必然不存在,所以把第二个值对应的hash表的值置为0,因为第二个值选它不可能找到匹配,然后进入下一次迭代。

if(hashTable[NeedValue+offset])
{
result[count] = (int*)malloc(sizeof(int) * 3);
result[count][0] = nums[i] < NeedValue ? nums[i] : NeedValue;
result[count][1] = nums[i] > NeedValue ? nums[i] : NeedValue;

if(current >= result[count][1])
result[count][2] = current;
else if(current < result[count][1] && current >= result[count][0])
{
result[count][2] = result[count][1];
result[count][1] = current;
}
else
{
result[count][2] = result[count][1];
result[count][1] = result[count][0];
result[count][0] = current;
}

count++;
}

hashTable[NeedValue+offset] = 0;
hashTable[nums[i]+offset] = 0;
},
*returnSize = count;
}


如果需要的值刚好在,那么我们就找到了一个符合要求的三维组,然后我们按由小到大的顺序把它们排好,存到result中,然后把第二个数和第三个数对应的hash表的值置为0,因为如果之后再遇到第二个值,那么要想符合要求也只能找第三个值,而这我们已经找到过了,所以忽略掉,如果再遇到第三个值,那么它也只能找第二个值,所以同样忽略掉。另外如果需要的值不存在,同样把第二个值和第三个值对应的hash表的值置为0,其实第三个值的值已经是0,这就是说以后再遇到第二个值,可以忽略,因为它只能找第三个值,而第三个值不可取,所以不能成功。

下面是完整程序代码:

#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;

void twoSum(int* nums, int numsSize, int* returnSize, int *hashTable, int hTlen, int target, int start, int offset, int**result, int current) { int NeedValue; int count = *returnSize; for(int i = start; i < numsSize; i++) { if(!hashTable[nums[i]+offset]) continue; hashTable[nums[i]+offset]--; NeedValue = target - nums[i]; if(NeedValue + offset < 0 || NeedValue + offset > hTlen - 1) { hashTable[nums[i]+offset] = 0; continue; }
if(hashTable[NeedValue+offset])
{
result[count] = (int*)malloc(sizeof(int) * 3);
result[count][0] = nums[i] < NeedValue ? nums[i] : NeedValue;
result[count][1] = nums[i] > NeedValue ? nums[i] : NeedValue;

if(current >= result[count][1])
result[count][2] = current;
else if(current < result[count][1] && current >= result[count][0])
{
result[count][2] = result[count][1];
result[count][1] = current;
}
else
{
result[count][2] = result[count][1];
result[count][1] = result[count][0];
result[count][0] = current;
}

count++;
}

hashTable[NeedValue+offset] = 0;
hashTable[nums[i]+offset] = 0;
}
*returnSize = count;
}

int** threeSum(int* nums, int numsSize, int* returnSize) { if(numsSize == 0) return NULL; int min_element = 100000000; int max_element = -100000000; for(int i = 0; i < numsSize; i++) { if(min_element > nums[i]) min_element = nums[i]; if(max_element < nums[i]) max_element = nums[i]; } int offset = -1* min_element;

int *hashTable = (int*)malloc(sizeof(int) * (max_element - min_element + 1));

memset(hashTable, 0, sizeof(int) * (max_element - min_element + 1));
for(int i = 0; i < numsSize; i++)
{
hashTable[nums[i] + offset]++;
}

int **result = (int**)malloc(sizeof(int*) * 300);
*returnSize = 0;
for(int i = 0; i < numsSize; i++)
{
int target = -1 * nums[i];
int *newHashTable = (int*)malloc(sizeof(int) * (max_element - min_element + 1));
memcpy(newHashTable, hashTable, sizeof(int) * (max_element - min_element + 1));
if(newHashTable[nums[i] + offset] > 0)
newHashTable[nums[i] + offset]--;
else if(newHashTable[nums[i] + offset] == 0)
continue;
//else if(newHashTable[nums[i] + offset] < 0)
//cout<<"asdfadsfasdfasdfasdfasdf";
twoSum(nums, numsSize, returnSize, newHashTable, max_element - min_element + 1, target, i+1, offset, result, nums[i]);
hashTable[nums[i] + offset] = 0;

}

return result;
}

int main()
{
int nums[300], numsSize = 0, returnSize = 0;

cout<<"Input the numSize:"<<endl;
cin>>numsSize;

for(int i = 0; i < numsSize; i++)
{
cin>>nums[i];
}

int **result = threeSum(nums, numsSize, &returnSize);

for(int i = 0; i < returnSize; i++)
{
cout<<result[i][0]<<" "<<result[i][1]<<" "<<result[i][2]<<endl;;
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode