摆烂仔打卡之LeetCode热题100(三数之和)
因为数组最开始已经被初始化变成有序数组,所以在使用双指针的时候既能遍历完全不漏解,又能提高效率,节省更多资源。不同的三元组是 [-1,0,1] 和 [-1,-1,2]。又是一个新知识点,结尾附体会。注意,输出的顺序和三元组的顺序并不重要。左指针右移 → 数字变大 → 总和增大。右指针左移 → 数字变小 → 总和减小。看了这一篇对双指针的感悟比较ok'答案中不可以包含重复的三元组。唯一可能的三元组和
·
体会:双指针!又是一个新知识点,结尾附体会
老规矩先上题目
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0 。
int compare(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
if (numsSize < 3) {
*returnSize = 0;
*returnColumnSizes = NULL;
return NULL;
}
qsort(nums, numsSize, sizeof(int), compare);
int maxResultSize = numsSize * numsSize;
int** result = (int**)malloc(maxResultSize * sizeof(int*));
*returnColumnSizes = (int*)malloc(maxResultSize * sizeof(int));
*returnSize = 0;
for (int i = 0; i < numsSize - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1, right = numsSize - 1;
while (left < right) {
int total = nums[i] + nums[left] + nums[right];
if (total == 0) {
result[*returnSize] = (int*)malloc(3 * sizeof(int));
result[*returnSize][0] = nums[i];
result[*returnSize][1] = nums[left];
result[*returnSize][2] = nums[right];
(*returnColumnSizes)[*returnSize] = 3;
(*returnSize)++;
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
} else if (total < 0) {
left++;
} else {
right--;
}
}
}
return result;
}
这是结合ai捣鼓出来的全代码
#include <stdio.h>
#include <stdlib.h>
int compare(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
// 处理边界情况
if (numsSize < 3) {
*returnSize = 0;
*returnColumnSizes = NULL;
return NULL;
}
// 先排序数组
qsort(nums, numsSize, sizeof(int), compare);
// 分配内存:最多可能有 n^2/2 个解
int maxResultSize = numsSize * numsSize / 2;
int** result = (int**)malloc(maxResultSize * sizeof(int*));
*returnColumnSizes = (int*)malloc(maxResultSize * sizeof(int));
*returnSize = 0;
// 遍历数组,使用双指针法
for (int i = 0; i < numsSize - 2; i++) {
// 跳过重复的数字
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = numsSize - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
// 找到满足条件的三元组
result[*returnSize] = (int*)malloc(3 * sizeof(int));
result[*returnSize][0] = nums[i];
result[*returnSize][1] = nums[left];
result[*returnSize][2] = nums[right];
(*returnColumnSizes)[*returnSize] = 3;
(*returnSize)++;
// 跳过重复的元素
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
// 移动指针继续寻找
left++;
right--;
} else if (sum < 0) {
// 和太小,左指针右移
left++;
} else {
// 和太大,右指针左移
right--;
}
}
}
return result;
}
int main() {
int nums[] = {-1, 0, 1, 2, -1, -4};
int numsSize = sizeof(nums) / sizeof(nums[0]);
int returnSize;
int* returnColumnSizes;
int** result = threeSum(nums, numsSize, &returnSize, &returnColumnSizes);
printf("找到 %d 个三元组:\n", returnSize);
for (int i = 0; i < returnSize; i++) {
printf("[%d, %d, %d]\n", result[i][0], result[i][1], result[i][2]);
free(result[i]);
}
free(result);
free(returnColumnSizes);
return 0;
}
因为数组最开始已经被初始化变成有序数组,所以在使用双指针的时候既能遍历完全不漏解,又能提高效率,节省更多资源
-
左指针右移 → 数字变大 → 总和增大
-
右指针左移 → 数字变小 → 总和减小
看了这一篇对双指针的感悟比较ok'
更多推荐
所有评论(0)