1. 程式人生 > >Two Sum(初談雙指標)

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,當然收穫也是良多的,這道題也有雜湊的做法,現在還不是很懂,在後面的學習中會慢慢補上這一部分,也會談一下對棧、堆的理解。新手上路,錯誤之處,還望指正!