每天一道LeetCode-----逆序链表
Reverse Linked List
原題鏈接Reverse Linked List
逆序一個鏈表
首先是一個比較容易理解的方法,假設鏈表為A->B->C->D->E->F
通常在解決與鏈表有關的額問題時會預設置一個頭節點,
設置方法為
ListNode* header = new ListNode(-1); header->next = head; //head是鏈表的第一個節點注:以下將head稱為鏈表的首節點,header稱為鏈表的頭節點
這種方法有以下幾個好處
- 設置后鏈表的首節點(head)的前驅節點不再是nullptr,方便更改鏈表的首節點
- 可用于解決鏈表首節點是空節點的情況
- 可通過header->next作為最后的結果返回
不過第一種解決方法不需要將頭節點(header)的后驅節點設置為首節點(head),作為一般性情況,剛開始的結果鏈表是空,所以
header->next = nullptr;獲得逆序鏈表的方法,依次遍歷原始鏈表,每遇到一個節點,就將其插入到header和header->next之間
以A->B->C->D->E->F鏈表為例
- 初始時鏈表為header, nullptr
- 遇到節點A時header, A, nullptr
- 遇到節點B時header, B, A, nullptr
- 遇到節點C時header, C, B, A, nullptr
- …
- 遇到節點F時header, F, E, D, C, B, A, nullptr
代碼比較容易
/*** 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) {ListNode* header = new ListNode(-1);ListNode* cur = head;while(cur){//將cur插入到header和header->next之間ListNode* next = cur->next;cur->next = header->next;header->next = cur;cur = next;}head = header->next;delete header;return head;} };當然了,這種方法多少顯得有些笨拙,第二種方法看起來就有點,唔,高端
其實可以直接遍歷的時候逆序,而不是以插入為主要操作,所以最開始頭節點的后驅節點設置成首節點即可
header->next = head; //head是鏈表第一個節點此時的鏈表大概是這個樣子
header->A->B->C->D->E->F->nullptr
逆序的思路是,一個一個逆序,即先逆序兩個,再逆序三個,…,直到逆序所有節點
逆序兩個,即逆序A->B
僅僅是交換位置嘛~額,換個角度看,實際上是將B提到header的后面,此時變為
header->B->A->C->D->E->F->nullptr
逆序三個,即逆序A->B->C
在上一步的基礎上,把C提到header的后面,此時變為
header->C->B->A->D->E->F->nullptr
啦啦啦~實際上就是依次將遍歷到的節點放在header的后面。其實就是小考慮一小部分,最后由部分到整體(算法思想叫啥來著?)
因為逆序后原鏈表的首節點(head)變為最后一個節點,所以實際上是將head的下一個節點提到header的后面(注意head->next一直在變)
代碼如下
/*** 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) {ListNode* header = new ListNode(-1);header->next = head;ListNode* cur = head;while(cur && cur->next){ListNode* next = cur->next;cur->next = next->next;//將next節點插入到header和header->next之間next->next = header->next;header->next = next;}head = header->next;delete header;return head;} };Reverse Linked List II
原題鏈接Reverse Linked List II
仍然是逆序,但是只逆序第m個節點到第n個節點之間(包括m和n)的節點
所以說上面高端的做法這里就顯得比較簡潔,不過還是先用第一種方法試一下
首先找到第m-1個節點作為header,然后將遍歷到的節點依次插入到header和header->next之間
所以就存在兩種情況,一種是在[m, n]范圍內的節點,另一種不是
- 如果節點在[m, n]范圍內,就將該節點插入到header和header->next之間
- 如果節點不在[m, n]范圍內,就將節點追加到鏈表末尾
代碼如下
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:ListNode* reverseBetween(ListNode* head, int m, int n) {ListNode* header = new ListNode(-1);ListNode* cur = head;ListNode* prev = header;ListNode* reverseHeader = nullptr;int count = 1;while(cur){//在[m, n]之間,prev作為header,將遍歷到的節點插入到header和header->next之間//在這個過程中需要保存第m個節點,因為在離開[m, n]區域后,之前第m個節點需要作為prev的新值if(count >= m && count <= n){if(count == m)reverseHeader = cur;ListNode* next = cur->next;cur->next = prev->next;prev->next = cur;cur = next;if(count == n)prev = reverseHeader;}//追加到末尾,不要忘記將prev->next置為nullptrelse{prev->next = cur;prev = cur;cur = cur->next;prev->next = nullptr;}++count;}head = header->next;delete header;return head;} };額,終于發現這種方法的不足了(只要從代碼長度看就不咋地)
應用第二種方法,原鏈表中直接逆序,但只需要逆序[m, n]范圍內的元素
那么,可以先找到第m個節點,逆序n-m次即可
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:ListNode* reverseBetween(ListNode* head, int m, int n) {ListNode* header = new ListNode(-1);header->next = head;n -= m;//prev是第m-1個節點ListNode* prev = header;while(--m)prev = prev->next;//cur是第m個節點ListNode* cur = prev->next;//n已經變為n-mwhile(n--){//prev是第m-1個節點,也是逆序節點集的header節點ListNode* next = cur->next;cur->next = next->next;next->next = prev->next;prev->next = next;}head = header->next;delete header;return head;} };這兩道題主要是逆序鏈表問題,對于逆序節點可以依次將遇到的節點提到前面(方法二),這種方法比較高效,代碼也少:)
總結
以上是生活随笔為你收集整理的每天一道LeetCode-----逆序链表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 每天一道LeetCode-----将数字
- 下一篇: 每天一道LeetCode-----将字符