1. 程式人生 > >【leetcode】18. 4Sum(C)

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