C语言力扣第十五题之三数之和。三指针法

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。


示例 1:

输入:nums = [-1, 0, 1, 2, -1, -4]
输出:[[-1, -1, 2], [-1, 0, 1]]

示例 2:

输入:nums = []
输出:[]

示例 3:

输入:nums = [0]
输出:[]


提示:

0 <= nums.length <= 3000
- 105 <= nums[i] <= 105

来源:力扣(LeetCode)
链接:https ://leetcode.cn/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

*返回大小为*returnSize的数组。

*数组的大小作为*returnColumnSizes数组返回。

*注意:返回的数组和*columnSizes数组都必须是malloced,假设调用方调用free()。


1: 快速排序,之后使用双指针遍历对应的位置,求解
2: 主要是在确定了第一个值,后通过双指针的方式,确定出来其余两个值
3: 将结果统计出来

nums = [-1,0,1,2,-1,-4]
快排结果如下:
nums = [    -4,     -1,     -1,     0,      1,      2]
三指针       ^        ^                             ^
             |        |                             |
            Left    Middle                      indexRight
初始状态              |
                     遍历 middle 和 indexRight的区间
Left + Middle + indexRight = -4  + -1 + 2  = -3 < 0
Middle移动 一直移动    Middle == -1 , 0 , 1 < 0 
Left = -4的没有符合的
************************
移动 Left
nums = [    -4,     -1,     -1,     0,      1,      2]
                     ^       ^                      ^       
                     |       |                      |
                    Left    Middle                indexRight   
Left + Middle + indexRight = -1  + -1 + 2  = 0 记录结果
************************
移动Middle 
nums = [    -4,     -1,     -1,     0,      1,      2]
                     ^              ^               ^       
                     |              |               |
                    Left            Middle        indexRight 
  Left + Middle + indexRight = -1  + 0 + 2  > 0 不符合
************************
indexRight 
nums = [    -4,     -1,     -1,     0,      1,      2]
                     ^              ^       ^       
                     |              |       |
                    Left            Middle indexRight 
  Left + Middle + indexRight = -1  + 0 + 1  = 0 符合
此时Left等于-1时的结果遍历结束。
************************
移动 Left
nums = [    -4,     -1,     -1,     0,      1,      2]
                             ^        
                             |      
                            Left     
Left和一个Left值一样,会得到相同的结果不符合
************************
移动 Left
nums = [    -4,     -1,     -1,     0,      1,      2]
                                    ^        
                                    |      
                                    Left    
开始遍历只有1种可能 0, 1 ,2 不符合
************************
移动 Left
nums = [    -4,     -1,     -1,     0,      1,      2]
                                            ^        
                                            |      
                                            Left    
Left的值 大于 0了,因为Left是最小的,所以不能三个数相加等于0
直接退出返回
************************
int cmp(const void *a, const void *b)
{
	return *(int*)a - *(int*)b;
}

int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes)
{
	*returnSize = 0;
	if (numsSize < 3)
		return NULL;
	qsort(nums, numsSize, sizeof(int), cmp);
	int **ans = (int **)malloc(sizeof(int *) * numsSize  *numsSize);
	*returnColumnSizes = (int *)malloc(sizeof(int) * numsSize * numsSize);
	int i, j, k, sum;

	int indexLeft = 0;
	int indexMiddle = 0;
	int indexRight = 0;
	//快排过后,使用三指针 遍历
	//左边遍历到倒数第三位即可
	for (indexLeft = 0; indexLeft < numsSize - 2; indexLeft++)
	{
		if (nums[indexLeft] > 0)
		{
			//因为是快排的结果,所以如果出现大零的
			//后面的值都是大于0的
			return ans;
		}

		//如果值相同 则不需要遍历
		if (indexLeft > 0 && nums[indexLeft] == nums[indexLeft - 1])
			continue;
		indexMiddle = indexLeft + 1;
		indexRight = numsSize - 1;

		//双指遍历 找到所有的可能
		while (indexMiddle < indexRight)
		{
			sum = nums[indexLeft] + nums[indexMiddle] + nums[indexRight];

			if (sum == 0)
			{
				ans[*returnSize] = (int*)malloc(sizeof(int) * 3);
				(*returnColumnSizes)[*returnSize] = 3;
				ans[*returnSize][0] = nums[indexLeft];
				ans[*returnSize][1] = nums[indexMiddle];
				ans[*returnSize][2] = nums[indexRight];
				*returnSize += 1;
				//过滤相等的值
				while (indexMiddle < indexRight && nums[indexMiddle] == nums[++indexMiddle]);
				while (indexMiddle < indexRight && nums[indexRight] == nums[--indexRight]);
			}
			else if (sum > 0)
			{
				//左边递减
				indexRight--;
			}
			else
			{
				//右边递增
				indexMiddle++;
			}
		}
	}
	return ans;
}


int main()
{
	int nums[6] = { -1, 0, 1, 2, -1, -4 };
	int numsSize = 6;
	int i = 0, j = 0;
	int returnSize;// 表示返回的二维数组的行数
	int **returnColumnSize;// 指向列数组指针的指针
	// 注意:列数组在哪我们无从得知,也不需要知道,
	// 我们只要知道有个一阶指针指向它就行了,我把它叫做列数组指针
	int **ans = threeSum(nums, numsSize, &returnSize, returnColumnSizes);
	// &returnSize 引用传值
	// 最后一个参数我认为也可以是 int *returnColumnSize,然后传入&returnColumnSizes,效果是一样的
	for (i = 0; i < (*returnSize); i++) {
		for (j = 0; j < (*returnColumnSize)[i]; j++)
			printf("%d", ans[i][j]);
		printf("\n");
	}
	return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

D了一天bug忘了编译

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值