Two Sum(初談雙指標)
昨天晚上遇到這麼一個題目,然後聽到了關於“雙指標”的使用。好了,言歸正傳,先來看一看這個題目:
Given an array of integers, return indices of the two numbers such that they add up to a specific target. |
---|
You may assume that each input would have exactly one solution |
Example: |
---|
Given nums = [2, 7, 11, 15], target = 9, |
Because |
nums[0] + nums[1] = 2 + 7 = 9, return [0, 1]. |
1. 巢狀迴圈解法
首先說一下我自己在面向這個題的時候的解法:首先,我認為對該無序陣列進行排序,目的是為了減少遍歷時間。以題目給的資料為例:
sort(nums, nums + numsSize);
int *Result = (int*)malloc(sizeof(int)* 2);
for (int i = 0; i < numsSize - 1; i++){
for (int j = i + 1; j < numsSize; j++){
if (nums[i] + nums[j] == target){ //寫入
Result[0] = nums[i];
Result[1] = nums[j];
}
if (nums[i] + nums[j] > target) //跳出判斷
break;
}
}
return Result;
但是,在通過第一組測試資料之後,出現了新的問題:
Example: |
---|
Given nums = [3, 2, 4], target = 6, |
Because |
nums[1] + nums[2] = 2 + 4 = 6, return [1, 2]. |
但是由於在前面經過了排序,陣列元素的下標已經改變,所以,最後的輸出結果變成了[0, 2]。
於是,不得不採用最原始的解決辦法,巢狀迴圈全部遍歷,雖然大大增加了運算時間,但是總算解決了問題,當然,程式碼實現也就更簡單了,具體程式碼如下:
int *Result = (int*)malloc(sizeof(int)* 2);
for (int i = 0; i < numsSize - 1; i++){
for (int j = i + 1; j < numsSize; j++){
if (nums[i] + nums[j] == target){
Result[0] = i;
Result[1] = j;
}
}
}
return Result;
這裡還有一個細節的問題,就是這個:int *Result = (int)malloc(sizeof(int)* 2);
一開始的時候,返回的這個陣列我是直接定義的:int Result[2];
但是發現返回後在主函式內列印是不可行的,雖然後來改為了動態分配解決了這個問題,但是並不知道原因所在,現在瞭解到:
函式內開闢的這個陣列空間,是存在於棧當中的,函式在完成功能後,當時使用的記憶體空間是拒絕再被訪問的,你返回的那個陣列的首地址—Result,也是毫無意義,然後動態分配的空間是存在於堆當中的,是一個共享的空間,大家都可以使用,所以,即使函式完成了功能,也是可以被主函式訪問的。
關於堆和棧的更多詳細的內容,我借鑑前輩的經驗,也寫了一點,有興趣的可以到這裡去看看關於堆和棧(直接點我)
2.雙指標解法
雙指標解法的優化之處在於僅需要一次遍歷就可以達到目的。好,直接進入主題:
首先對該無序陣列進行排序,隨後用兩個變數指向陣列的開頭和結尾:這裡我們使用low和high,分別指向nums[0]和nums[numsSize];因為已經進行過排序,如果nums[low]+nums[high] < target,則說明low指向的數太小,需要往後移動;反之,則是high指向的數太大,需要前移,當兩者相等,遍歷結束 。
完全程式碼如下:
int compi(const void *a, const void *b){ //C的qsort要用的函式
return (*(int*)a - *(int*)b);
}
int* twoSum(int* nums, int numsSize, int target){
bool flag = true;
int* Result = (int*)malloc(sizeof(int)* 2);
int* temp = (int*)malloc(sizeof(int)*numsSize); //複製陣列來找真正的下標
for (int i = 0; i < numsSize; i++)
temp[i] = nums[i];
qsort(nums, numsSize,sizeof(nums[0]),compi);
int low = 0;
int high = numsSize - 1;
while (low < high){
if (nums[low] + nums[high] < target)
low++;
else if (nums[low] + nums[high] > target)
high--;
else
break;
}
//flag用於解決nums[low]和nums[high]相等造成無法給Result[1]賦值的情況
for (int i = 0; i < numsSize; i++){
if (temp[i] == nums[low] && flag==true)
{
Result[0] = i;
flag = false;
}
if (temp[i] == nums[high])
{
Result[1] = i;
}
}
//如果返回陣列的數值大小不正確,交換
if (Result[0] > Result[1]){
int temp = Result[0];
Result[0] = Result[1];
Result[1] = temp;
}
return Result;
}
修改了好一陣子,終於給了AC,當然收穫也是良多的,這道題也有雜湊的做法,現在還不是很懂,在後面的學習中會慢慢補上這一部分,也會談一下對棧、堆的理解。新手上路,錯誤之處,還望指正!