【leetcode】18. 4Sum(C)

Description:

Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note:
The solution set must not contain duplicate quadruplets.

Example1:

Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.
A solution set is:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]

[ 题目链接 ]

解题思路:
先使用归并排序(mergeSort)对数组进行排序;
设置四个指针base1,base2,start,end依次分别指向四个数字,
其中start和end移动的频率最高,base2其次,base1移动最慢;
整体就是3Sum的加长版。

提交代码:

void merge(int* nums, int left, int mid, int right)
{
	int len = right - left + 1;
	int* tmp = (int*)malloc(len * sizeof(int));
	int i = left, j = mid + 1, k = 0;

	while (i <= mid && j <= right)
		tmp[k++] = nums[i] < nums[j] ? nums[i++] : nums[j++];
	while (i <= mid)
		tmp[k++] = nums[i++];
	while (j <= right)
		tmp[k++] = nums[j++];

	for (k = 0; k < len; k++)
		nums[left++] = tmp[k];
}

void mergeSort(int* nums, int left, int right)
{
	if (left >= right)	return;

	int mid = (left + right) / 2;

	mergeSort(nums, left, mid);
	mergeSort(nums, mid + 1, right);
	merge(nums, left, mid, right);
}



int** fourSum(int* nums, int numsSize, int target, int* returnSize)
{
	if (numsSize < 4)
	{
		*returnSize = 0;
		return NULL;
	}

	int i, j, sum;
	int base1, base2, start, end, top = 0;

	int alen = numsSize * (numsSize - 1)*(numsSize - 2)*(numsSize - 3) / 24;
	int** a = (int**)malloc(alen * sizeof(int*));

	mergeSort(nums, 0, numsSize - 1);
	for (i = 0; i < numsSize - 3; i++)
	{
		base1 = i;
		if (target > 0 && nums[base1] > target)	break;
        //为提高速度,target大于0 同时nums[base1]也大于0时,直接break此次循环
        if (base1 > 0 && (nums[base1] == nums[base1 - 1])) continue;
        //nums[base1]和前一个数一样的话直接跳到下一个循环,
        //设置base1>0是当base1=0时避免访问到nums[-1]

		for (j = i + 1; j < numsSize - 2; j++)
		{
			if (j!=(i+1)&&nums[j] == nums[j - 1]) continue;
            //如果nums[base2]和base2上一个指向的数一样的话,直接跳过此次循环
            //增加判别条件j!=(i+1)是为了避免nums={0,0,0,0}这种情况
			base2 = j;
			start = base2 + 1;
			end = numsSize - 1;
			while (start < end)
			{
				sum = nums[base1] + nums[base2] + nums[start] + nums[end];
				if (sum == target)
				{
                    //如果当前的base1、base2、start、end和上一组一样,则不录入返回的数组a中
					if (top>0&&nums[base1] == a[top - 1][0] && 
						nums[base2] == a[top - 1][1] &&
						nums[start] == a[top - 1][2] && 
						nums[end] == a[top - 1][3])
						start++;
					
					else
					{
						a[top] = (int*)malloc(4 * sizeof(int));   //how to define top?
						a[top][0] = nums[base1];
						a[top][1] = nums[base2];
						a[top][2] = nums[start];
						a[top][3] = nums[end];
						top++; start++; end--;
					}
				}
				else if (sum < target)
					start++;
				else
					end--;
			}
		}
	}
	*returnSize = top;
	return a;
}

运行结果:
在这里插入图片描述

其他:
1.如果主函数中分配了数组内存,记得free掉;
2.刚开始为了调试方便,在主函数里面我设置了nums数组大小为8,后面测试的需要的数组大于8 了显示报错:
在这里插入图片描述

这个报错的原因就是数组越界了,但是报错的地方却是在return 0之后。希望自己以后会记住这个报错;
3.之前我认为,如果base1大于target,因为base2、start、end都大于base1,那么四数之和也必然大于target可以直接跳过。
但是我忽略了负数的情况,例如:
target=-11,base1=-5,base2=-5,start=-1,end=0时显然符合情况,但如果我不考虑负数的情况就会少返回几组数;
4.为了避免返回的数组中有重复的情况,我设置避免重复的方式是:
在这里插入图片描述
如果当前nums[base2]和nums[base2-1]一样,则跳过此次循环
(设置j!=(i+1)是为了避免例如【nums={0,0,0,0},target=0】的这种情况。此时当base2=0时,nums[base2]==nums[base2-1],但是不能跳过这个循环,因为0+0+0+0=0,符合情况)

还有就是:
在这里插入图片描述

当当前的nums[base1],nums[base2],nums[start],nums[end]和上一组已经记录在a数组里面的一样时,只将第三个数start的位置加一下:
例如-4 -3 -2 -1 0 0 1 2 3 4 target=1时,
如果nums[base1]=-2,nums[base2]=第一个0,nums[start]=1,nums[end]=2时,
-2+0+1+2符合情况,这四个数会被记录到a二维数组中。
当继续移动base2到第二个0时,也符合情况,但是不能继续录入到a二维数组中,不然会造成重复录入

猜你喜欢

转载自blog.csdn.net/AXIMI/article/details/83068902