21. 合並兩個有序鏈表(C++)


題目

將兩個升序鏈表合並為一個新的 升序 鏈表並返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。

示例:

輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4

分析與題解

題解一(遞歸)

在忽略空鏈表的情況下,利用遞歸的思想依次對兩個鏈表的元素進行比較和合並,大致思路如下:

\[\left\{\begin{array}{ll} \operatorname{list} 1[0]+\operatorname{merge}(\operatorname{list} 1[1:], \operatorname{list} 2) & \operatorname{list} 1[0]<\operatorname{list} 2[0] \\ \operatorname{list} 2[0]+\operatorname{mer} g e(\operatorname{list} 1, \operatorname{list} 2[1:]) & \text {otherwise} \end{array}\right.\]

也就是說,兩個鏈表頭部值較小的一個節點與剩下元素的 merge 操作結果合並。如果 l1 或者 l2 一開始就是空鏈表 ,那么沒有任何操作需要合並,所以我們只需要返回非空鏈表。否則,我們要判斷 l1l2 哪一個鏈表的頭節點的值更小,然后遞歸地決定下一個添加到結果里的節點。如果兩個鏈表有一個為空,遞歸結束。

代碼如下:

/**
* Definition for singly-linked list.
* struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        //如果某個指針為空指針,直接返回飛空指針即可
        if(l1 == nullptr)
            return l2;
        else if(l2 == nullptr)
            return l1;
        else if(l1->val < l2->val){
            l1->next = mergeTwoLists(l1->next,l2);
            return l1;
        }
        else{
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
 
    }
};

題解二(迭代)

我們可以用迭代的方法來實現上述算法。當l1l2都不是空鏈表時,判斷l1l2哪一個鏈表的頭節點的值更小,將較小值的節點添加到結果里,當一個節點被添加到結果里之后,將對應鏈表中的節點向后移一位。

首先,我們設定一個哨兵節點 prehead這可以在最后讓我們比較容易地返回合並后的鏈表。我們維護一個 prev 指針,我們需要做的是調整它的 next 指針。然后,我們重復以下過程,直到 l1 或者 l2 指向了 null :如果 l1 當前節點的值小於等於 l2 ,我們就把 l1 當前的節點接在prev節點的后面同時將 l1 指針往后移一位。否則,我們對 l2 做同樣的操作。最后不管將哪一個元素接在了后面,我們都需要把 prev 向后移一位。

在循環終止的時候, l1l2 至多有一個是非空的。由於輸入的兩個鏈表都是有序的,所以不管哪個鏈表非空,它包含的所有元素都比前面已經合並鏈表中的所有元素都要大。這意味着我們只需要簡單地將非空鏈表接在合並鏈表的后面,並返回合並鏈表即可。

image-20200814161256383

注意在while循環終止時,非空鏈表的剩余元素還沒有與prev連接起來。所以退出循環后還需要再在指定下next為非空剩余鏈表的頭指針。代碼如下:

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* preHead = new ListNode(-1);
 
        ListNode* prev = preHead;
        while (l1 != nullptr && l2 != nullptr) {
            if (l1->val < l2->val) {
                prev->next = l1;
                l1 = l1->next;
            } else {
                prev->next = l2;
                l2 = l2->next;
            }
            prev = prev->next;
        }
 
        // 合並后 l1 和 l2 最多只有一個還未被合並完,我們直接將鏈表末尾指向未合並完的鏈表即可
        prev->next = l1 == nullptr ? l2 : l1;
 
        return preHead->next;
    }
};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM