1. 程式人生 > >LeetCode 單鏈表專題 (一)

LeetCode 單鏈表專題 (一)

listnode ptr 時間 lis class toc ref nod link

目錄

  • LeetCode 單鏈表專題 <c++>
    • \([2]\) Add Two Numbers
    • \([92]\) Reverse Linked List II
    • \([86]\) Partition List
    • \([82]\) Remove Duplicates from Sorted List II
    • \([61]\) Rotate List
    • \([19]\) Remove Nth Node From End of List

LeetCode 單鏈表專題 <c++>

\([2]\) Add Two Numbers

模擬,註意最後判斷進位是否為1。
時間復雜度 \(O(n)\)

class Solution {
public:
    ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
        ListNode ans(-1);
        int carry = 0;
        auto p1 = l1, p2 = l2;
        auto p = &ans;
        while (p1 != nullptr || p2 != nullptr) {
            int val1, val2;
            if (p1 == nullptr) { val1 = 0; }
            else {
                val1 = p1->val;
                p1 = p1->next;
            }
            if (p2 == nullptr) { val2 = 0; }
            else {
                val2 = p2->val;
                p2 = p2->next;
            }
            int sum = (val1 + val2 + carry) % 10;
            carry = (val1 + val2 + carry) / 10;
            p = p->next = new ListNode(sum);
        }
        if(carry) p->next = new ListNode(carry);
        return ans.next;
    }
};

\([92]\) Reverse Linked List II

給定鏈表,翻轉第m個結點到第n個結點。
從第m+1個結點開始,在第m-1個結點之後的位置用頭插法插入新結點,可以避免使用棧。
時間復雜度 \(O(n)\)

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        ListNode res(-1);
        auto p = head, p_res = &res;
        for(int i = 1; i <= m-1; i++){
            p_res = p_res->next = new ListNode(p->val); // new list next node
            p = p->next; // origin list next node
        }
        auto prev = p_res;
        p_res = p_res->next = new ListNode(p->val);
        auto last = p_res; 
        p = p->next;
        for(int i = m+1; i <= n; i++){
            prev->next = new ListNode(p->val);
            prev->next->next = p_res;
            p_res = prev->next;
            p = p->next;
        }
        last->next = p;
        return res.next;
    }
};

\([86]\) Partition List

鏈表拼接。
時間復雜度 \(O(n)\)
(c++)搞清楚了實體用.,指針用->調用屬性和方法。
(c++)new 構造方法(參數)返回的是同類型指針。

class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        ListNode dummy_l(-1);
        ListNode dummy_r(-1);
        auto dummy_l_p = &dummy_l, dummy_r_p = &dummy_r;
        for(auto p = head; p; p = p->next){
            if(p->val<x){
                dummy_l_p = dummy_l_p->next = p;
            } 
            else {
                dummy_r_p = dummy_r_p->next = p;
            }
        }
        dummy_l_p->next = dummy_r.next;
        dummy_r_p->next = nullptr;
        return dummy_l.next;
    }  
};

\([82]\) Remove Duplicates from Sorted List II

如果有元素重復出現,刪掉該元素及其復制。
時間復雜度 \(O(n)\)

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        ListNode dummy(-1);
        auto prev = &dummy;
        bool flag = false;
        for(auto p = head; p; p = p->next){
            while(p->next!=nullptr && p->next->val == p->val){
                p->next = p->next->next;
                flag = true;
            }
            if(flag){
                flag = false;
                prev->next = p->next;
            }
            else prev = prev->next = p;
        }
        return dummy.next;
    }
};

\([61]\) Rotate List

先遍歷求出長度length。k可能大於等於length,所以對length取模。從length-k處斷開原鏈表,斷開處為新鏈表頭結點,原頭結點接到原尾結點後面。
時間復雜度 \(O(n)\)

class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if(head == nullptr) return head;
        int length = 1;
        auto cur = head;
        for(; cur->next; cur = cur->next) length++;
        k = k % length;
        if(k == 0) return head;
        ListNode dummy(-1);
        dummy.next = head;
        auto cut = &dummy;
        for(int i = 0; i<length - k; i++) cut = cut->next;
        dummy.next = cut->next;
        cur->next = head;
        cut->next = nullptr; // 記得斷開,避免形成環,會TLE。
        return dummy.next;
    }
};

\([19]\) Remove Nth Node From End of List

刪掉鏈表倒數第n個結點,要求只遍歷一遍。
兩個指針p,q。一個先走n步,然後兩個一起走。
時間復雜度 \(O(n)\)

/**
 * Status: Accepted
 * Runtime: 12 ms
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode dummy(-1);
        dummy.next = head;
        auto p = &dummy, q = &dummy;
        int cnt = 0;
        while(p!=nullptr) {
            if(cnt>n) q = q->next;
            p = p->next;
            cnt++;
        }
        q->next = q->next->next;
        return dummy.next;
    }
};

這份代碼跑了12ms。因為循環中有判斷語句。
下面是優化後的代碼

/**
 * Status: Accepted
 * Runtime: 8 ms
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode dummy(-1);
        dummy.next = head;
        auto p = &dummy, q = &dummy;
        for(int i = 0; i<=n; i++) p = p->next;
        while(p!=nullptr) {
            q = q->next;
            p = p->next;
        }
        auto tmp = q->next;
        q->next = q->next->next;
        delete tmp;
        return dummy.next;
    }
};

LeetCode 單鏈表專題 (一)