--- title: 題解:鏈結串列 Linked List tags: solution --- # [LeetCode] 237 - Delete Node in a Linked List - 題目連結:[237 - Delete Node in a Linked List](https://leetcode.com/problems/delete-node-in-a-linked-list/) ```cpp= void deleteNode(ListNode* node) { node->val = node->next->val; node->next = node->next->next; } ``` --- # [LeetCode] 21 - Merge Two Sorted Lists - 題目連結:[21 - Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/) 開一個新的list,並把兩串list給合併, 下面用了一個很值得參考的邏輯寫法,之後介紹「Merge Sort」時也會看到這樣的寫法: ```cpp= ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { ListNode* head = new ListNode(); ListNode* cur = head; while(l1 != nullptr || l2 != nullptr){ if(l1 != nullptr && l2 == nullptr || l1->val < l2->val){ cur = cur->next = new ListNode(l1->val); l1 = l1->next; } else{ cur = cur->next = new ListNode(l2->val); l2 = l2->next; } } return head->next; } ``` --- # [Geeks] Doubly linked list Insertion at given position - 題目連結:[Doubly linked list Insertion at given position](https://practice.geeksforgeeks.org/problems/insert-a-node-in-doubly-linked-list/1) ```cpp= void addNode(Node *head, int pos, int data) { while(pos--) head = head->next; Node *temp = new Node(data); temp->prev = head; temp->next = head->next; head->next = temp; } ``` --- # [Geeks] Delete node in Doubly Linked List - 題目連結:[Delete node in Doubly Linked List](https://practice.geeksforgeeks.org/problems/delete-node-in-doubly-linked-list/1) ```cpp= Node* deleteNode(Node *head, int x) { if(x==1) return head->next; Node *cur = head; while(--x) cur = cur->next; cur->prev->next = cur->next; return head; } ``` --- # [LeetCode] 141 - Linked List Cycle - 題目連結:[141 - Linked List Cycle](https://leetcode.com/problems/linked-list-cycle/) 我們可以將val設定成一個超出範圍的值( $[-10^5,10^5]$ ),這樣就可以記錄該點是否有被走過了。 ```cpp= bool hasCycle(ListNode *head) { while(head != NULL){ if(head->val == 100005) return true; head->val = 100005; head = head->next; } return false; } ``` --- # [CSES] Josephus Problem I - 題目連結:[Josephus Problem I](https://cses.fi/problemset/task/2162) 這一題的正確解法並不是用串列來解, 但是這題由於跳過的數量小,故亦可利用Circlular Linked List來解 (~~當做練習~~)。 利用單向串列來解,建構完後將頭尾進行相接 (圖例中是將8接到1): ![](https://i.imgur.com/Wyz5V8b.png) 接下來,從1開始數,跳過(skip)1人並移出(rm=remove)1人,直到剩下最後1人為止: ![](https://cdn.discordapp.com/attachments/458265468470427659/827184735964102666/unknown.png) ( 此圖之移出順序為:2, 4, 6, 8, 3, 7, 5, 1 ) Linked List version ( Time: 0.04s ) : ```cpp= # include <bits/stdc++.h> using namespace std; struct Node{ int num; Node* ptr; Node(Node *p, const int &n){ num = n; ptr = p; } }; int main() { ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); Node* llist; int N,n; cin>>N; Node *head = new Node(nullptr,1); Node *cur = head; // building circular linked list for(n = 2 ; n<=N ; n++) cur = cur->ptr = new Node(nullptr,n); cur->ptr = head; // traversing while(--N){ cur = cur->ptr; cout<<cur->ptr->num<<' '; cur->ptr = cur->ptr->ptr; } cout<<cur->num; } ``` Array version ( Time: 0.03s ) : ```cpp= # include <bits/stdc++.h> using namespace std; struct Node{ int num; int next; }; int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); int N,n; cin>>N; Node k[200005]; // building circular list k[1].num = 1; for(n = 2 ; n<=N ; n++){ k[n].num = n; k[n-1].next = n; } k[N].next = 1; // traversing (total move N times) n = 1; while(N--){ cout<<k[k[n].next].num<<' '; n = k[n].next = k[k[n].next].next; } } ``` > 為什麼用陣列來寫會比用指標來寫還要快呢? > 其實執行的時間就只差在「建構(building circlular list)」的步驟而已。 > > 這是結論:new 的執行速度會比直接宣告變數的執行速度還要來得慢 > > 文章參考:[Why should C++ programmers minimize use of 'new'?](https://stackoverflow.com/questions/6500313/why-should-c-programmers-minimize-use-of-new) 以下是幾個網路上看到非常有意思的解法: - 數學解(圓):[How to cheat death — Josephus Problem](https://medium.com/@RahulDharan/how-to-cheat-death-josephus-problem-ae31d37af7ed) - 動態規劃解法:[GeeksforGeeks - Josephus problem | Set 1 (A O(n) Solution)](https://www.geeksforgeeks.org/josephus-problem-set-1-a-on-solution/) - Wiki:[約瑟夫斯問題](https://zh.wikipedia.org/wiki/%E7%BA%A6%E7%91%9F%E5%A4%AB%E6%96%AF%E9%97%AE%E9%A2%98) (推導動態規劃解與另一種的數學解) --- # [LeetCode] 938 - Range Sum of BST - 題目連結:[938 - Range Sum of BST](https://leetcode.com/problems/range-sum-of-bst/) 利用遞迴的方式,把每個節點看成有左和右 這兩個分支, 若這個節點符合題目要求的範圍,則將節點上的值回傳回去。 可以看成一個簡單的遞迴式子: $f(x)=\begin{cases} 0 &\text{if } x=\text{null} \\ f(x_{\text{left}}) + f(x_{\text{right}}) + x_{\text{val}} & \text{if }x_{\text{val}} \in[\text{low, high}] \\ f(x_{\text{left}}) + f(x_{\text{right}}) & \text{if }x_{\text{val}} ∉[\text{low, high}] \\ \end{cases}$ ```cpp= int rangeSumBST(const TreeNode* root, int low, int high) { if(root == nullptr) return 0; return ((low <= root->val && root->val <= high) ? root->val : 0) + rangeSumBST(root->left,low,high) + rangeSumBST(root->right,low,high); // current + left + right // if the current value on the interval [low,high], the result will be add. } ``` ###### posted date: `2021.4.8`