LeetCode | 24.兩兩交換鏈表中的節(jié)點(diǎn)

這次來(lái)寫(xiě)一下 LeetCode 的第 24 題,兩兩交換鏈表中的節(jié)點(diǎn)。

題目描述

題目直接從 LeetCode 上截圖過(guò)來(lái),題目如下:

image

上面的題就是 兩兩交換鏈表中的節(jié)點(diǎn) 題目的截圖,同時(shí) LeetCode 給出了一個(gè)函數(shù)的定義,然后要求實(shí)現(xiàn)鏈表兩兩交換的函數(shù)體。函數(shù)定義如下:

/**

 * Definition for singly-linked list.

 * struct ListNode {

 *     int val;

 *     struct ListNode *next;

 * };

 */

struct ListNode* swapPairs(struct ListNode* head){

}

從定義上看,是一個(gè)單鏈表,單鏈表只能順著節(jié)點(diǎn)的指針依次找下去,而不能往回找。

問(wèn)題分析

這個(gè)題目看似簡(jiǎn)單,其實(shí)還是有幾個(gè)坑在里面的。聽(tīng)我慢慢道來(lái)。

先來(lái)看看,鏈表最初的情況,如下圖:

image

最初鏈表的頭指向第一個(gè)節(jié)點(diǎn),我們首先要交換的是第一個(gè)節(jié)點(diǎn)和第二個(gè)節(jié)點(diǎn),根據(jù)指針來(lái)看,只要讓第一個(gè)節(jié)點(diǎn)的 next 指向第三個(gè)節(jié)點(diǎn),然后讓第二個(gè)節(jié)點(diǎn)的 next 指向第一個(gè)節(jié)點(diǎn)就可以了。在交換之前,首先要有一個(gè)指針(pre)指向第一個(gè)節(jié)點(diǎn)、還要有一個(gè)指針(cur)指向第二個(gè)節(jié)點(diǎn),當(dāng)然再準(zhǔn)備一個(gè)指針(new)指向第三個(gè)節(jié)點(diǎn)。有了這些指針,就可以完成我們的交換了,如下圖:

image

當(dāng)交換完成以后,就接著移動(dòng)這三個(gè)指針,進(jìn)行下一次的交換。這樣就構(gòu)成了一個(gè)循環(huán),怎么來(lái)判斷是否循環(huán)?讓 new = head,當(dāng) new 為 NULL 或者 new->next 為 NULL 的時(shí)候,就說(shuō)明沒(méi)有節(jié)點(diǎn)或者只剩一個(gè)節(jié)點(diǎn)了,就不用再交換了,這樣循環(huán)就結(jié)束了。

以上看似完成了,其實(shí)還是有一個(gè)問(wèn)題,我們接著推第二步交換試試。如下圖:

image

開(kāi)始第二輪交換的時(shí)候,指針的位置是這樣的,然后按照前面的指針交換的方式進(jìn)行交換。圖下圖:

image

交換完后的鏈表成了這個(gè)樣子,但是仔細(xì)觀(guān)察,不知道是否觀(guān)察出了問(wèn)題。我們的 4 號(hào)節(jié)點(diǎn)沒(méi)有辦法遍歷到了。因?yàn)?1 號(hào)節(jié)點(diǎn)的指針仍然指向著 3 號(hào)節(jié)點(diǎn),而經(jīng)過(guò)交換,要把 4 號(hào)節(jié)點(diǎn)放到 3 號(hào)節(jié)點(diǎn)的前面。那么,也就是說(shuō),除了要完成 3 號(hào)節(jié)點(diǎn)和 4 號(hào)節(jié)點(diǎn)的交換,還要修正 1 號(hào)節(jié)點(diǎn)中 next 的指向。而此時(shí),我們已經(jīng)沒(méi)有指針指向 1 號(hào)節(jié)點(diǎn)了。所以,我們?cè)黾右粋€(gè)指針 tmp 來(lái)指向 pre 指針就可以了,以后通過(guò) tmp 指針的 next 來(lái)修正即可。修正后如下圖:

image

當(dāng)以后兩個(gè)節(jié)點(diǎn)交換完成后,將 pre 指針賦值給 tmp 指針即可。

這樣看似完成了,那么還有問(wèn)題么?問(wèn)題還是有的,我們的 head 指針一直指向的是 1 號(hào)節(jié)點(diǎn),但是實(shí)際的鏈表頭節(jié)點(diǎn)已經(jīng)是 2 號(hào)節(jié)點(diǎn)了。當(dāng)函數(shù)執(zhí)行完成時(shí),需要返回新的鏈表頭節(jié)點(diǎn),要怎么返回呢?我這里又增加了一個(gè)新的指針 result 來(lái)記錄新的頭節(jié)點(diǎn),當(dāng)循環(huán)完成以后,直接返回 result 就可以了。

上面的步驟就算完成了,幾個(gè)問(wèn)題其實(shí)都是我在寫(xiě)代碼的時(shí)候遇到的。雖然步驟是完成了,但是我覺(jué)得我的代碼應(yīng)該還是有簡(jiǎn)化的空間的。暫時(shí)沒(méi)有再去考慮了。

代碼實(shí)現(xiàn)

上面說(shuō)了那么多,其實(shí)代碼反倒不是很復(fù)雜。代碼如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* swapPairs(struct ListNode* head){
    struct ListNode *new = head;
    struct ListNode *pre = NULL;
    struct ListNode *cur = NULL;

    // 如果鏈表本身就是空的,那么就直接返回好了
    if (head == NULL) {
        return head;
    }

    // 不管鏈表有多少節(jié)點(diǎn),只要大于等于兩個(gè)節(jié)點(diǎn),那么新的鏈表頭都是第二個(gè)節(jié)點(diǎn)
    struct ListNode *result = head;
    if (head->next != NULL) {
        result = head->next;
    }

    struct ListNode *tmp = NULL;

    while (new != NULL && new->next != NULL) {
        // 設(shè)置 pre 和 cur 的位置
        pre = new;
        cur = new->next;
        new = new->next->next;
        // 交換
        pre->next = cur->next;
        cur->next = pre;
        // 這就是在第二次以及以后交換中要修正的部分
        if (tmp != NULL) tmp->next = cur;
        // 為了修正,需要保留當(dāng)前交換的前一個(gè)節(jié)點(diǎn)
        tmp = pre;
    }

    return result;
}

注釋是我剛剛加上去的,其實(shí)自己整理了一遍,發(fā)現(xiàn)思路比當(dāng)時(shí)寫(xiě)的時(shí)候清晰了許多。整理和總結(jié)真的是挺重要的。

提交結(jié)果

在寫(xiě)完 swapPairs 函數(shù)體后,點(diǎn)擊右下角的 “執(zhí)行代碼”,然后觀(guān)察 “輸出” 和 “預(yù)期結(jié)果” 是否一致,一致的話(huà)就點(diǎn)擊 “提交” 按鈕。點(diǎn)擊 “提交” 按鈕后,系統(tǒng)會(huì)使用更多的測(cè)試用例來(lái)測(cè)試我們寫(xiě)的函數(shù)體,如果所有的測(cè)試用例都通過(guò)了,那么就會(huì)給出 “通過(guò)” 的字樣,如果沒(méi)有通過(guò),會(huì)給出失敗的那一組測(cè)試用例,我們繼續(xù)修改代碼。我們以上代碼 “提交” 以后的截圖如下:

image

我覺(jué)得在內(nèi)存消耗上應(yīng)該可以更小一些,我為了截這個(gè)圖,重新提交了代碼,在提交代碼前還修改了幾行代碼,內(nèi)存消耗也由 5.5 MB 變?yōu)榱?5.4 MB,通過(guò)梳理自己還是能找到改進(jìn)空間,給自己點(diǎn)個(gè)贊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容