【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二維陣列中,不然會造成重複錄入