三数之和
题目重复如下:
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
思路如下:
- 先用快排将数组排序;
- 在遍历数组,选择数a;
- 两个指针i,j从剩下的数组中分别从最左边和最右边开始遍历,其中b=nums[i],c=nums[j],找到a+b+c=0的记录下来;
- 当i<j条件不成立时,退出内层循环,i++;
- 注意不重复条件,当a与上一次a值相同时,本次外层循环不用进行,i++;
当a,b,c与前一次完全相同时,本次内层循环无效。
代码
C版
/**
* Return an array of arrays of size *returnSize.
* Note: The returned array must be malloced, assume caller calls free().
*/
//先将数字排序
void quickSort(int a[], int left, int right) {
if (left >= right)
return;
//枢纽单元的选取为最左边、最中间、最右边三个数的中位数,使得左右分布尽量均匀
int key;
int index = 0;
if (a[left] > a[right] && a[left] < a[(left + right) / 2] || a[left]<a[right] && a[left] > a[(left + right) / 2]) {
key = a[left];
index = left;
}
else if (a[right] > a[left] && a[right] < a[(left + right) / 2] || a[right]<a[left] && a[right] > a[(left + right) / 2]) {
key = a[right];
index = right;
}
else {
key = a[(left + right) / 2];
index = (left + right) / 2;
}
//将key的值放在第一位
int temp = a[left];
a[left] = a[index];
a[index] = temp;
//实现大数右边小数左边
int i = left, j = right;
while (i < j) {
while (i<j&&a[j]>key) { j--; }
if (i < j) {
a[i++] = a[j];
}
while (i < j&&a[i] < key) { i++; }
if (i < j) {
a[j--] = a[i];
}
}
//最后退出一定是i==j,因为某个(i或者j)在等待时,另一个++或--,当++或--到与另一个相等时
//就退出,这时相等的下标位置就是等待着插入元素的位置,也就是最后要放key值的位置。
a[i] = key;
//递归地处理左边,递归地处理右边
quickSort(a, left, i - 1);
quickSort(a, i + 1, right);
}
int** threeSum(int* nums, int numsSize, int* returnSize) {
//快排
quickSort(nums, 0, numsSize - 1);
//定元素a,然后用双指针从两边开始找
//先用最多个数数组考虑
int maxLength = numsSize/3 ;
int length = 0;
int **a = (int**)malloc(sizeof(int*)*maxLength);
for (int i = 0; i < maxLength; i++) {
a[i] = (int*)malloc(sizeof(int) * 3);
}
int i = 0, j, k;
int la=0x7fffffff, lb= 0x7fffffff, lc= 0x7fffffff;//由于数组是有序的,因此重复的元组必定是连续的
while (i < numsSize - 2) {
j = i + 1;
k = numsSize - 1;
if (la == nums[i]) {
i++;
continue;
}
while (j < k) {
if (nums[i] + nums[j] + nums[k] == 0) {
if (!(nums[j] == lb && nums[k] == lc)) {
if (length > maxLength-1) {
int * temp = (int*)malloc(sizeof(int) * 3);
temp[0] = nums[i];
temp[1] = lb = nums[j];
temp[2] = lc = nums[k];
a = (int**)realloc(a,(++length)*sizeof(int*));
a[length - 1] = temp;
}
else {
a[length][0] = nums[i];
a[length][1] = lb = nums[j];
a[length][2] = lc = nums[k];
length++;
}
}
j++;
k--;
}
else if (nums[i] + nums[j] + nums[k] > 0) {
k--;
}
else if (nums[i] + nums[j] + nums[k] < 0) {
j++;
}
}
la = nums[i];
i++;
}
*returnSize = length;
return a;
}
4个数字的代码(经过整理比3个数字的更清晰,3个数字的出现了数组越界访问的问题,但vs没报错)
int** fourSum(int* nums, int numsSize, int target, int* returnSize) {
for (int i = 0; i < numsSize - 1; i++) {
for (int j = i + 1; j < numsSize; j++) {
if (nums[i] > nums[j]) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
int **a = (int**)malloc(sizeof(int*)*numsSize);
int outputSize = 0, maxSize = numsSize, incre = numsSize / 4;
for (int i = 0; i < maxSize; i++) {
a[i] = (int*)malloc(sizeof(int) * 4);
}
for (int i = 0; i < numsSize - 3; i++) {
if (i == 0 || nums[i] > nums[i - 1]) {
for (int j = i + 1; j < numsSize - 2; j++) {
if (j == i + 1 || nums[j] > nums[j - 1]) {
int m = j + 1, n = numsSize - 1;
while (m < n) {
if (nums[i] + nums[j] + nums[m] + nums[n] == target) {
if (outputSize >= maxSize) {
maxSize += incre;
a = (int**)realloc(a, sizeof(int*)*(maxSize));
for (int t = outputSize; t < outputSize + incre; t++) {
a[t] = (int*)malloc(sizeof(int) * 4);
}
}
a[outputSize][0] = nums[i];
a[outputSize][1] = nums[j];
a[outputSize][2] = nums[m];
a[outputSize][3] = nums[n];
outputSize++;
m++;
n--;
while (m<numsSize&&nums[m] == nums[m - 1]) { m++; }
while (n>-1&&nums[n] == nums[n + 1]) { n--; }
}
else if (nums[i] + nums[j] + nums[m] + nums[n] < target) {
m++;
while (m < numsSize&&nums[m] == nums[m - 1]) { m++; }
}
else if (nums[i] + nums[j] + nums[m] + nums[n] > target) {
n--;
while (n > -1 && nums[n] == nums[n + 1]) { n--; }
}
}
}
}
}
}
*returnSize = outputSize;
return a;
}
python 版
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
res =[]
i = 0
for i in range(len(nums)):
if i == 0 or nums[i]>nums[i-1]:
l = i+1
r = len(nums)-1
while l < r:
s = nums[i] + nums[l] +nums[r]
if s ==0:
res.append([nums[i],nums[l],nums[r]])
l +=1
r -=1
while l < r and nums[l] == nums[l-1]:
l += 1
while r > l and nums[r] == nums[r+1]:
r -= 1
elif s>0:
r -=1
else :
l +=1
return res