建立連結串列的虛擬頭結點 203 Remove Linked List Element,82,147,148,237
阿新 • • 發佈:2018-12-25
該邏輯對於刪除第一個元素不適用。
這樣的程式碼不優美
/** * 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) {while(head!=NULL && head->val == val){ ListNode* delNode = head; head = delNode ->next; delete delNode; } if(head == NULL) return NULL; ListNode* cur = head; while(cur->next != NULL){if(cur->next->val == val){ //刪除 ListNode* delNode = cur->next; cur->next = delNode->next; delete delNode; } else cur = cur->next; } return head; } };
可以設定一個虛擬的頭結點:
/** * 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* dummyHead = new ListNode(0); dummyHead->next = head; ListNode* cur = dummyHead; while(cur->next != NULL){ if(cur->next->val == val){ //刪除 ListNode* delNode = cur->next; cur->next = delNode->next; delete delNode; } else cur = cur->next; } ListNode* retNode = dummyHead->next; delete dummyHead; return retNode; } };
這道題想了好久,原因是要把重複的所有元素都刪除,這裡設立一個duplicate標誌位來記錄當前cur是否與下一個結點重複。
/** * 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* h = new ListNode(-1); h->next = head; ListNode* pre = h; ListNode* cur = head; while(cur!=NULL){ bool duplicate = false; while(cur->next!=NULL && cur->val==cur->next->val){ ListNode* delNode = cur; cur = cur->next; delete delNode; duplicate = true; } if(duplicate == false){ pre = cur; cur = cur->next; } else{ pre->next = cur->next; ListNode* delNode = cur; cur = cur->next; delete delNode; } } return h->next; } };
歸併兩個有序的連結串列。
/** * 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* h = new ListNode(-1); ListNode* cur = h; ListNode* cur1 = l1; ListNode* cur2 = l2; while(cur1 != NULL && cur2 != NULL){ if(cur1->val <= cur2->val){ cur->next = cur1; cur1 = cur1->next; } else{ cur->next = cur2; cur2 = cur2->next; } cur = cur->next; } if(cur1 != NULL){ cur->next = cur1; } if(cur2 != NULL){ cur->next = cur2; } ListNode* ret = h->next; delete h; return ret; } };
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* swapPairs(ListNode* head) { ListNode* dummyHead = new ListNode(0); dummyHead->next = head; ListNode* p = dummyHead; while(p->next && p->next->next){ ListNode* node1 = p->next; ListNode* node2 = node1->next; ListNode* next = node2->next; node2->next = node1; node1->next = next; p->next = node2; p = node1; } ListNode* ret = dummyHead->next; delete dummyHead; return ret; } };
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* reverseKGroup(ListNode* head, int k) { if(!head || k==1) return head; ListNode* dummy = new ListNode(-1); ListNode* pre = dummy, *cur = head; dummy->next = head; int i = 0; while(cur){ i++; if(i%k == 0){ pre = reverseOneGroup(pre, cur->next); cur = pre->next; } else{ cur = cur->next; } } return dummy->next; } ListNode* reverseOneGroup(ListNode* pre, ListNode* next){ ListNode* last = pre->next; ListNode* cur = last->next; while(cur!=next) { last->next = cur->next; cur->next = pre->next; //注意這裡是指向pre->next pre->next = cur; cur = last->next; } return last; //返回需要翻轉的最後一個元素 } };
用連結串列來實現插入排序。
思路:建立一個輔助的新連結串列,並且使用一個指標遍歷原連結串列,每次將原連結串列中的一個節點插入到新連結串列的合適位置(即該節點的值大於新連結串列上的節點的值,又小於後一節點的值)。最後將新連結串列的頭部返回即可。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* insertionSortList(ListNode* head) { if(head == NULL || head->next == NULL) return head; ListNode* pre = new ListNode(-1), *ans = pre; //建立一個新連結串列的頭結點,並用一個臨時變數來儲存 ListNode* cur = head; //cur是原連結串列的指標 while(cur != NULL){ //每次迴圈前重置pre為頭結點,保證每次都從頭到尾遍歷 pre = ans; while(pre->next != NULL && pre->next->val < cur->val){ pre = pre->next; } //此時,pre->next->val大於cur->val,應把cur插入到pre後 //儲存原連結串列當前節點的下一個節點 ListNode* tmp = cur->next; //插入cur到pre後 cur->next = pre->next; pre->next = cur; cur = tmp; //cur在原連結串列中後移一位 } return ans->next; } };
本題適用於歸併排序,難點是:怎麼樣找到分治時的middle指標,採用快慢指標的思想。快指標一次走兩步,慢指標一次走一步,當快指標走到頭時,慢指標剛好走到中間位置,此位置即為middle的位置。
快慢指標思想:
快慢指標是指指標移動的步長,快指標移動的快,慢指標移動的慢,例如可以讓快指標一次移動兩個步長,讓慢指標一次移動一個步長。
快慢指標有兩個比較重要的應用:
1、判斷連結串列是否為單鏈表
2、在有序連結串列中尋找中位數
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* sortList(ListNode* head) { //將一個連結串列平分為兩個連結串列 if(!head || !head->next) return head; ListNode* slow = head, *fast = head, *pre = head; while(fast && fast->next){ pre = slow; slow = slow->next; fast = fast->next->next; } pre->next = NULL; return merge(sortList(head), sortList(slow)); } ListNode* merge(ListNode* l1, ListNode* l2){ ListNode* dummy = new ListNode(-1); ListNode* cur = dummy; while(l1 && l2){ if(l1->val < l2->val){ cur->next = l1; l1 = l1->next; } else{ cur->next = l2; l2 = l2->next; } cur = cur->next; } if(l1) cur->next = l1; if(l2) cur->next = l2; return dummy->next; } };
改變節點的值來解決問題。
/** * 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) { if(node == NULL) return; if(node->next == NULL){ delete node; node = NULL; return; } node->val = node->next->val; ListNode* delNode = node->next; node->next = delNode->next; delete delNode; return; } };