三数之和
方案一
基于两数之和计算
如果nums[i] > 0则不需要管后面
C-源代码
int compareInt(const void *a, const void *b)
{
return *(int *)a - *(int *)b;
}
void two_sum(int *nums, int left, int right, int target, int **results, int *count) {
while (left < right) {
int diff = target - nums[left];
if (diff < nums[right]) {
while (--right > left && nums[right] == nums[right + 1]) {
}
} else if (diff > nums[right]) {
while (++left < right && nums[left] == nums[left - 1]) {
}
} else {
results[*count] = malloc(3 * sizeof(int));
results[*count][0] = -target;
results[*count][1] = nums[left];
results[*count][2] = nums[right];
(*count)++;
while (++left < right && nums[left] == nums[left - 1]) {}
while (--right > left && nums[right] == nums[right + 1]) {}
}
}
}
int** threeSum(int* nums, int numsSize, int* returnSize) {
if (numsSize < 3) {
return NULL;
}
qsort(nums, numsSize, sizeof(*nums), compareInt);
*returnSize = 0;
int **results = malloc(sizeof(int *) * (((numsSize * (numsSize - 1) * (numsSize - 2))) / (3 * 2 * 1)));
for (int i = 0; i < numsSize; i++) {
if ((i == 0 && nums[i] <= 0) || ((i > 0 && nums[i] != nums[i - 1]) && nums[i] <= 0)) {
two_sum(nums, i + 1, numsSize - 1, -nums[i], results, returnSize);
}
}
return results;
}
void test_0015()
{
int arr[6] = { -1, 0, 1, 2, -1, -4 };
// int arr[4] = { 1, 2, -2, -1 };
int count = 0;
int **ret = threeSum(arr, 4, &count);
if (ret) {
for (int i = 0; i < count; i++) {
int *temp = ret[i];
printf("%d->%d->%d\n",temp[0],temp[1],temp[2]);
}
}
}
方案二
对原数组进行排序,然后开始遍历排序后的数组,这里注意不是遍历到最后一个停止,而是到倒数第三个就可以了。这里我们可以先做个剪枝优化,就是当遍历到正数的时候就break,为啥呢,因为我们的数组现在是有序的了,如果第一个要fix的数就是正数了,那么后面的数字就都是正数,就永远不会出现和为0的情况了。然后我们还要加上重复就跳过的处理,处理方法是从第二个数开始,如果和前面的数字相等,就跳过,因为我们不想把相同的数字fix两次。对于遍历到的数,用0减去这个fix的数得到一个target,然后只需要再之后找到两个数之和等于target即可。我们用两个指针分别指向fix数字之后开始的数组首尾两个数,如果两个数和正好为target,则将这两个数和fix的数一起存入结果中。然后就是跳过重复数字的步骤了,两个指针都需要检测重复数字。如果两数之和小于target,则我们将左边那个指针i右移一位,使得指向的数字增大一些。同理,如果两数之和大于target,则我们将右边那个指针j左移一位,使得指向的数字减小一些
C++-源代码
#include <iostream>
#include <queue>
#include <unordered_map>
using namespace std;
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
// 对原数组进行排序
sort(nums.begin(), nums.end());
if (nums.empty() || nums.back() < 0 || nums.front() > 0) {
return {};
}
for (int k = 0; k < nums.size(); ++k) {
// 当遍历到正数的时候就break
if (nums[k] > 0) {
break;
}
if (k > 0 && nums[k] == nums[k - 1]) {
continue;
}
// 对于遍历到的数,用0减去这个fix的数得到一个target
int target = 0 - nums[k];
int i = k + 1;
int j = nums.size() - 1;
while (i < j) {
// 用两个指针分别指向fix数字之后开始的数组首尾两个数,如果两个数和正好为target,则将这两个数和fix的数一起存入结果中
if (nums[i] + nums[j] == target) {
res.push_back({nums[k], nums[i], nums[j]});
// 检测重复数字
while (i < j && nums[i] == nums[i + 1]) {
++i;
}
// 检测重复数字
while (i < j && nums[j] == nums[j - 1]) {
--j;
}
++i;
--j;
}
// 如果两数之和小于target,则我们将左边那个指针i右移一位
else if (nums[i] + nums[j] < target) {
++i;
}
// 如果两数之和大于target,则我们将右边那个指针j左移一位
else {
--j;
}
}
}
return res;
}
};
网友评论