鏈表問題(一)-LeetCode 138、382、203、143、141、142(有環鏈表入環節點,複製複雜鏈表)

  • 2019 年 12 月 13 日
  • 筆記

鏈表問題(一):LeetCode #138 382 203 143 141 142

1

編程題

【LeetCode #138】複製帶隨機指針的複雜鏈表

解題思路: 如圖所示:

class Solution {  public:      Node* copyRandomList(Node* head) {          if(head == nullptr)  return nullptr;          Node* cur = head;          Node* pNext = nullptr;          // 第一步:1 -> 1' -> 2 -> 2' ...          while(cur != nullptr){              pNext = cur->next;              cur->next = new Node(cur->val);              cur->next->next = pNext;              cur = pNext;          }          // 第二步:修改random指針為cur->random->next          cur = head;          Node* copyNode = nullptr;          while(cur != nullptr){              pNext = cur->next->next;              copyNode = cur->next;              copyNode->random = ((cur->random == nullptr) ? nullptr : cur->random->next);              cur = pNext;          }          cur = head;          Node* res = cur->next;          while(cur != nullptr){              pNext = cur->next->next;              copyNode = cur->next;              cur->next = pNext;              copyNode->next = (pNext != nullptr) ? pNext->next : nullptr;              cur = pNext;          }          return res;      }  };  

來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/copy-list-with-random-pointer/

【LeetCode #382】鏈表的隨機節點

給定一個單鏈表,隨機選擇鏈表的一個節點,並返回相應的節點值。保證每個節點被選的概率一樣。 進階: 如果鏈表十分大且長度未知,如何解決這個問題?你能否使用常數級空間複雜度實現?

示例: // 初始化一個單鏈表 [1,2,3]. ListNode head = new ListNode(1); head.next = new ListNode(2); head.next.next = new ListNode(3); Solution solution = new Solution(head); // getRandom()方法應隨機返回1,2,3中的一個,保證每個元素被返回的概率相等。 solution.getRandom();

解題思路:

首先遍歷得到鏈表的長度,然後使用rand函數獲取隨機值,在找到對應節點!

class Solution {  public:      /** @param head The linked list's head.          Note that the head is guaranteed to be not null, so it contains at least one node. */      Solution(ListNode* head) {          phead = head;          while(head != nullptr){              size++;              head = head->next;          }      }        /** Returns a random node's value. */      int getRandom() {          ListNode* cur = phead;          int k = rand() % size;          for(int i = ; i < k; i++){              cur = cur->next;          }          return cur->val;      }  private:      int size = ;      ListNode* phead;  };  

來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/linked-list-random-node

【LeetCode #203】移除鏈表元素

刪除鏈表中等於給定值 val 的所有節點。

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

解題思路:

由於有可能是頭結點被刪除,因此需要使用哨兵節點dummy,在遍歷刪除中只使用一個指針pre,由於在循環中使用了pre->next->next, 因此while中的條件應該為pre->next != nullptr.

class Solution {  public:      ListNode* removeElements(ListNode* head, int val) {          ListNode* dummy = new ListNode(-1);  // pre指向dummy節點          dummy->next = head;          ListNode* pre = dummy;          while(pre->next != nullptr){              if(pre->next->val == val){                  pre->next = pre->next->next;                }else{                  pre = pre->next;              }          }          return dummy->next;      }  };  

來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/remove-linked-list-elements/

【LeetCode #143】重排鏈表

給定一個單鏈表 L:L0→L1→…→Ln-1→Ln , 將其重新排列後變為:L0→Ln→L1→Ln-1→L2→Ln-2→… 你不能只是單純的改變節點內部的值,而是需要實際的進行節點交換。

示例 1: 給定鏈表 1->2->3->4, 重新排列為 1->4->2->3.

解題思路:

將每個節點的指針放入vector中,然後進行連接,直接原地O(1)太難了,我記不住。。。

class Solution {  public:      void reorderList(ListNode* head) {          if(head == nullptr) return;          vector<ListNode*> vec;          while(head != nullptr){              vec.push_back(head);              head = head->next;          }          int left = , right = vec.size()-1;          while(left < right){              vec[left]->next = vec[right];              vec[right--]->next = vec[++left];          }          vec[left]->next = nullptr;      }  };  

來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/reorder-list

【LeetCode #141】環形鏈表

給定一個鏈表,判斷鏈表中是否有環。

為了表示給定鏈表中的環,我們使用整數 pos 來表示鏈表尾連接到鏈表中的位置(索引從 0 開始)。如果 pos 是 -1,則在該鏈表中沒有環。

示例 1: 輸入:head = [3,2,0,-4], pos = 1 輸出:true 解釋:鏈表中有一個環,其尾部連接到第二個節點。

解題思路:

使用快慢指針,慢指針一次走一步,快指針一次走兩步,如果有環,必定相遇,否則快指針會指向nullptr。

class Solution {  public:      bool hasCycle(ListNode *head) {          if(head == nullptr ||          head->next == nullptr ||          head->next->next == nullptr) return false;   // 兩個節點以上才會有環            ListNode *slow = head, *fast = head;          while(fast != nullptr){              slow = slow->next;              fast = (fast->next != nullptr) ? fast->next->next : nullptr;              if(slow == fast) return true;          }          return false;      }  };  

來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/linked-list-cycle

【LeetCode #142】環形鏈表II

給定一個鏈表,返回鏈表開始入環的第一個節點。如果鏈表無環,則返回 null。 為了表示給定鏈表中的環,我們使用整數 pos 來表示鏈表尾連接到鏈表中的位置(索引從 0 開始)。如果 pos 是 -1,則在該鏈表中沒有環。

說明:不允許修改給定的鏈表。

示例 1: 輸入:head = [3,2,0,-4], pos = 1 輸出:tail connects to node index 1 解釋:鏈表中有一個環,其尾部連接到第二個節點。

解題思路:

仍然是快慢指針,快指針一次走兩步,慢指針一次走一步,上一題只需要判斷有環無環即可,因此只需要相遇一次就好了,但這一題需要返回入環節點,因此需要相遇兩次!在第一次相遇後,將慢指針指向頭部位置,同時快指針改為一次走一步,第二次相遇的節點即為入環節點!

class Solution {  public:      ListNode *detectCycle(ListNode *head) {          if(head == nullptr || head->next == nullptr ||          head->next->next == nullptr)  return nullptr;            ListNode *slow = head, *fast = head;          while(fast != nullptr){              slow = slow->next;              fast = (fast->next != nullptr) ? fast->next->next : nullptr;              if(slow == fast){                  break;              }          }          if(fast == nullptr)  return nullptr;          slow = head;          while(slow != fast){              slow = slow->next;              fast = fast->next;          }          return slow;      }  };  

來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/linked-list-cycle-ii

Tags: