1. 程式人生 > >Leetcode ---- 連結串列簡單題

Leetcode ---- 連結串列簡單題

複習了一下連結串列。下面做了一些簡單題。

 

237. 刪除連結串列中的元素

題目:

請編寫一個函式,使其可以刪除某個連結串列中給定的(非末尾)節點,你將只被給定要求被刪除的節點。

現有一個連結串列 -- head = [4,5,1,9],它可以表示為:

    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.

說明:

  • 連結串列至少包含兩個節點。
  • 連結串列中所有節點的值都是唯一的。
  • 給定的節點為非末尾節點並且一定是連結串列中的一個有效節點。
  • 不要從你的函式中返回任何結果。

 

思路:

這道題很巧妙,函式只給了一個結點。題目要求是刪除該結點。那麼我們只需要將上個結點的後繼指向下一個結點。然而上一結點的資訊我們並不知道。所以,我們只能將這一結點替代下一結點,下一結點沒有結點指向。

 

程式:

/**
 * 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) {
        ListNode *p = node->next;
        node->val = p->val;
        node->next = p->next;
    }
};

 

203. 移除連結串列元素

題目:

刪除連結串列中等於給定值 val 的所有節點。

示例:

輸入: 1->2->6->3->4->5->6, val = 6
輸出: 1->2->3->4->5

 

思路:

由於這是一個單鏈表,刪除節點需要上一非目標節點指向該節點後續的非目標節點,因此,需要兩個指標,指標一是隻指向非目標節點的,而指標二是用來判斷節點的。

 

程式:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode *res = new ListNode(-1);
        ListNode *p = res;
        ListNode *q = head;
        
        
        while (q != NULL){
            if (q->val != val){
                p->next = q;
                p = p->next;
            }
            q = q->next;  
        }
        p->next = NULL;
        return res->next;
    }
};

 

83. 刪除排序連結串列中的重複元素

題目:

給定一個排序連結串列,刪除所有重複的元素,使得每個元素只出現一次。

示例 1:

輸入: 1->1->2
輸出: 1->2

示例 2:

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

思路:

這題思路比較簡單,有序、不重複,直接判斷當前值和下一值即可。

程式

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

 

876. 連結串列的中間結點

 

題目:

給定一個帶有頭結點 head 的非空單鏈表,返回連結串列的中間結點。

如果有兩個中間結點,則返回第二個中間結點。

示例 1:

輸入:[1,2,3,4,5]
輸出:此列表中的結點 3 (序列化形式:[3,4,5])
返回的結點值為 3 。 (測評系統對該結點序列化表述是 [3,4,5])。
注意,我們返回了一個 ListNode 型別的物件 ans,這樣:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.

示例 2:

輸入:[1,2,3,4,5,6]
輸出:此列表中的結點 4 (序列化形式:[4,5,6])
由於該列表有兩個中間結點,值分別為 3 和 4,我們返回第二個結點。

 

提示:

  • 給定連結串列的結點數介於 1 和 100 之間。

 

思路:

這道題求中點,很容易想到快慢指標,速度快一倍,當快指標指向NULL時,慢指標正好指向中點。

 

程式:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        ListNode *fast,*slow;
        fast = head;
        slow = head;
        while (fast != NULL && fast->next != NULL){
            slow = slow->next;
            fast = fast->next->next;
        }
        
        return slow;
    }
};

 

 

141. 環形連結串列

 

題目:

給定一個連結串列,判斷連結串列中是否有環。

進階:
你能否不使用額外空間解決此題?

 

思路:

依題意,我們可知道,該環只能在連結串列末尾的,不可能在中間和首。那麼,可以想象,當一個指標進入環後會無限迴圈下去。我們只需再放一個指標從頭進入,且速度比第一個指標慢即可。它們最終會在環內相遇。若沒環,則指標會指向NULL。

 

程式:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {  
        ListNode *fast,*slow;
        fast = head;
        slow = head;
          
        while (fast && fast->next){
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow){
                return true;
            }
        }
        return false;
        
/*        if (!head || !head->next)         // 判斷是迴圈連結串列,理解錯誤
            return false;
        ListNode *p = head;
        while (p->next){
            if (p->next == head)
                return true;
            p = p->next;
        }
        return false;
*/        
        
    }
};

 

160. 相交連結串列

 

題目:

編寫一個程式,找到兩個單鏈表相交的起始節點。

例如,下面的兩個連結串列

A:          a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗            
B:     b1 → b2 → b3

在節點 c1 開始相交。

注意:

  • 如果兩個連結串列沒有交點,返回 null.
  • 在返回結果後,兩個連結串列仍須保持原有的結構。
  • 可假定整個連結串列結構中沒有迴圈。
  • 程式儘量滿足 O(n) 時間複雜度,且僅用 O(1) 記憶體。

 

思路:

這題有兩個思路:

1. 得到兩個連結串列的長度,然後刪去長連結串列的頭,使得兩個連結串列相等。隨後從頭開始比對。

2. 若兩連結串列長度不相等,則正常比對到NULL也不會得到相等的。然而,兩個長度不一的連結串列各自加上對方,則會得到兩個相等長度的連結串列。由此,我們可以 第一次遇到NULL的時候,轉向另一條連結串列的頭,若相交,必會在交點相遇。

 

程式:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *p,*q;
        p = headA;
        q = headB;
        
        while (p != q){
            
            if (p == NULL){
                p = headB;
            }
            else{
                p = p->next;
            }
            
            if (q == NULL){
                q = headA;
            }
            else{
                q = q->next;
            }
        }
        return p;

      /*  int i = 0,j = 0;
        ListNode *p = headA,*q = headB;
        
        if (p == NULL || q == NULL)
            return NULL;
        
        while (p != NULL){
            p = p->next;
            i++;
        }
        while (q != NULL){
            q = q->next;
            j++;
        }
        
        int dis = i - j; 
        p = headA;
        q = headB;
        
        if (dis >= 0){
            while (dis != 0 && p != NULL){
                p = p->next;
                dis--;
            }
        }
        else{
            while (dis != 0 && q != NULL){
                q = q->next;
                dis++;
            }
        }
        while (p != NULL){
            if (p == q){
                return p;
            }
            p = p->next;
            q = q->next;
        }
        return NULL;*/
    }
};

 

21. 合併兩個有序連結串列

 

題目:

將兩個有序連結串列合併為一個新的有序連結串列並返回。新連結串列是通過拼接給定的兩個連結串列的所有節點組成的。 

示例:

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

 

思路:

1.  直接建立一個新連結串列,比對兩條連結串列,小的往裡面放即可。

2. 遞迴

 

程式:

/**
 * 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) {

        ListNode *head = new ListNode(-1);
        ListNode *p = head;
        if (l1 == NULL)
            return l2;
        if (l2 == NULL)
            return l1;
        
        while (l1 != NULL && l2 != NULL){
            if (l1->val < l2->val){
                p->next = l1;
                p = p->next;
                l1 = l1->next;
            }
            else{
                p->next = l2;
                p = p->next;
                l2 = l2->next;
            }
        }
        
        if (l1 == NULL && l2 != NULL){
            p->next = l2;
        }
        if (l2 == NULL && l1 != NULL){
            p->next = l1;
        }       
        return head->next;
        
        
        
/*        if (l1 == NULL)       // 遞迴
            return l2;
        if (l2 == NULL)
            return l1;
        
        if (l1->val < l2->val){
            l1->next = mergeTwoLists(l1->next,l2);
            return l1;
        }
        else{
            l2->next = mergeTwoLists(l2->next,l1);
            return l2;
        }*/

    }
};

 

 

206. 反轉連結串列

 

題目:

反轉一個單鏈表。

示例:

輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL

進階:
你可以迭代或遞迴地反轉連結串列。你能否用兩種方法解決這道題?

 

思路:

該題思路比較死板的方法就是建個數組(棧),先入再出。另一種就是用兩個指標,迴圈往回指即可。

程式:

/**
 * 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 == NULL||head->next == NULL){
            return head;
        }
        
        ListNode *ans = reverseList(head->next);
        head->next->next = head;
        head->next = NULL;
        return ans;     
        
/*        if (!head || !head->next)
            return head;
        
        ListNode *p = head;
        ListNode *tmp,*q;
        q = p->next;
        p->next = NULL;
        while (q){
            tmp = q->next;
            q->next = p;
            p = q;
            q = tmp;
        }
        return p;*/
    }
};