LeetCode刷題(十六)-----鏈表-------easy部分(Java、C++)

237. 刪除鏈表中的節點

請編寫一個函數,使其可以刪除某個鏈表中給定的(非末尾)節點,你將只被給定要求被刪除的節點。
現有一個鏈表 -- head = [4,5,1,9],它可以表示爲:

在這裏插入圖片描述
示例 1:
輸入: head = [4,5,1,9], node = 5
輸出: [4,1,9]
解釋: 給定你鏈表中值爲 5 的第二個節點,那麼在調用了你的函數之後,該鏈表應變爲 4 -> 1 -> 9.

示例 2:
輸入: head = [4,5,1,9], node = 1
輸出: [4,5,9]
解釋: 給定你鏈表中值爲 1 的第三個節點,那麼在調用了你的函數之後,該鏈表應變爲 4 -> 5 -> 9.
說明:
• 鏈表至少包含兩個節點。
• 鏈表中所有節點的值都是唯一的。
• 給定的節點爲非末尾節點並且一定是鏈表中的一個有效節點。
• 不要從你的函數中返回任何結果。

思路一:
方法:與下一個節點交換
從鏈表裏刪除一個節點node的最常見方法是修改之前節點的next指針,使其指向之後的節點。
在這裏插入圖片描述
因爲,我們無法訪問我們想要刪除的節點之前的節點,我們始終不能修改該節點的 next 指針。相反,我們必須將想要刪除的節點的值替換爲它後面節點中的值,然後刪除它之後的節點。
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
因爲我們知道要刪除的節點不是列表的末尾,所以我們可以保證這種方法是可行的。
在這裏插入圖片描述
複雜度分析
時間和空間複雜度都是:O(1)。
鏈接:https://leetcode-cn.com/problems/delete-node-in-a-linked-list/solution/shan-chu-lian-biao-zhong-de-jie-dian-by-leetcode/
思路二:
替身攻擊
在這裏插入圖片描述
鏈接:https://leetcode-cn.com/problems/delete-node-in-a-linked-list/solution/ti-shen-gong-ji-by-vailing/
我的:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    void deleteNode(ListNode* node) 
    {
        node -> val = node -> next -> val;
        node -> next = node -> next -> next;   
    }
};

206. 反轉鏈表

反轉一個單鏈表。
示例:
輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
進階:
你可以迭代或遞歸地反轉鏈表。你能否用兩種方法解決這道題?

思路一:
方法一:迭代
假設存在鏈表 1 → 2 → 3 → Ø,我們想要把它改成 Ø ← 1 ← 2 ← 3。
在遍歷列表時,將當前節點的 next 指針改爲指向前一個元素。由於節點沒有引用其上一個節點,因此必須事先存儲其前一個元素。在更改引用之前,還需要另一個指針來存儲下一個節點。不要忘記在最後返回新的頭引用!
在這裏插入圖片描述
複雜度分析
• 時間複雜度:O(n),假設n是列表的長度,時間複雜度是O(n)。
• 空間複雜度:O(1)。
方法二:遞歸
遞歸版本稍微複雜一些,其關鍵在於反向工作。假設列表的其餘部分已經被反轉,現在我該如何反轉它前面的部分?
假設列表爲:
在這裏插入圖片描述
若從節點n_{k+1}到n_{m}已經被反轉,而我們正處於n_{k}。
在這裏插入圖片描述
我們希望 n_{k+1}的下一個節點指向n_{k}。
所以,n_{k}.next.next = n_{k}。
要小心的是 n_{1}的下一個必須指向 Ø 。如果你忽略了這一點,你的鏈表中可能會產生循環。如果使用大小爲 2 的鏈表測試代碼,則可能會捕獲此錯誤。
在這裏插入圖片描述
複雜度分析
時間複雜度:O(n),假設 nn 是列表的長度,那麼時間複雜度爲 O(n)。
空間複雜度:O(n),由於使用遞歸,將會使用隱式棧空間。遞歸深度可能會達到 n層。

作者:LeetCode
鏈接:https://leetcode-cn.com/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-by-leetcode/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
思路二:
迭代:
在這裏插入圖片描述
在這裏插入圖片描述
遞歸:
在這裏插入圖片描述
我的:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) 
    {
        if(!head)
        {
            return nullptr;
        }    
        ListNode* first = head;
        ListNode* target = head -> next;
        while(target != nullptr)
        {
            first -> next = target -> next;
            ListNode* temp = target -> next;
            target -> next = head;
            head = target;
            target = temp;
        }
        return head;
    }
};

21. 合併兩個有序鏈表

將兩個有序鏈表合併爲一個新的有序鏈表並返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。 
示例:
輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4

思路一:
方法 1:遞歸
想法
我們可以如下遞歸地定義在兩個鏈表裏的merge操作(忽略邊界情況,比如空鏈表等):
在這裏插入圖片描述
也就是說,兩個鏈表頭部較小的一個與剩下元素的merge操作結果合併。
算法

我們直接將以上遞歸過程建模,首先考慮邊界情況。

特殊的,如果 l1 或者 l2 一開始就是 null ,那麼沒有任何操作需要合併,所以我們只需要返回非空鏈表。否則,我們要判斷 l1 和 l2 哪一個的頭元素更小,然後遞歸地決定下一個添加到結果裏的值。如果兩個鏈表都是空的,那麼過程終止,所以遞歸過程最終一定會終止。
在這裏插入圖片描述
複雜度分析
時間複雜度:O(n+m)。 因爲每次調用遞歸都會去掉 l1 或者 l2 的頭元素(直到至少有一個鏈表爲空),函數 mergeTwoList 中只會遍歷每個元素一次。所以,時間複雜度與合併後的鏈表長度爲線性關係。
空間複雜度:O(n+m)。調用 mergeTwoLists 退出時 l1 和 l2 中每個元素都一定已經被遍歷過了,所以 n + m個棧幀會消耗O(n+m)的空間。

方法 2:迭代
想法
我們可以用迭代的方法來實現上述算法。我們假設l1元素嚴格比l2元素少,我們可以將l2中的元素逐一插入l1中正確的位置。
算法
首先,我們設定一個哨兵節點 “prehead” ,這可以在最後讓我們比較容易地返回合併後的鏈表。我們維護一個 prev 指針,我們需要做的是調整它的 next 指針。然後,我們重複以下過程,直到 l1 或者 l2 指向了 null :如果 l1 當前位置的值小於等於 l2 ,我們就把 l1 的值接在 prev 節點的後面同時將 l1 指針往後移一個。否則,我們對 l2 做同樣的操作。不管我們將哪一個元素接在了後面,我們都把 prev 向後移一個元素。

在循環終止的時候, l1 和 l2 至多有一個是非空的。由於輸入的兩個鏈表都是有序的,所以不管哪個鏈表是非空的,它包含的所有元素都比前面已經合併鏈表中的所有元素都要大。這意味着我們只需要簡單地將非空鏈表接在合併鏈表的後面,並返回合併鏈表。
在這裏插入圖片描述
複雜度分析
時間複雜度:O(n+m) 。因爲每次循環迭代中,l1和l2只有一個元素會被放進合併鏈表中,while 循環的次數等於兩個鏈表的總長度。所有其他工作都是常數級別的,所以總的時間複雜度是線性的。

空間複雜度:O(1)。迭代的過程只會產生幾個指針,所以它所需要的空間是常數級別的。

作者:LeetCode
鏈接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-by-leetcode/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

思路二:
方法 1:遞歸
在這裏插入圖片描述
方法2:迭代
在這裏插入圖片描述
鏈接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-guan-fang-cban-b/
我的:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) 
    {
        if(l1 == NULL)
        {
            return l2;
        }
        else if(l2 == NULL)
        {
            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;
        }
    }
};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章