1.反轉連結串列:定義一個函式,輸入一個連結串列的頭節點,反轉該連結串列並輸出反轉後連結串列的頭節點。
(1)這道題是經典的題目了,用迭代的方式解決也是很容易的,程式碼量也不大。分享一個我個人做題的方式,我會先在題目開頭寫註釋,理清我結題的思路,然後寫程式碼就很容易了。
/** * 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 == nullptr || head->next == nullptr) return head; ListNode* pPre = nullptr; ListNode* pCur = head; ListNode* pNext = nullptr; while(pCur != nullptr) { pNext = pCur->next; pCur->next = pPre; pPre = pCur; pCur = pNext; }return pPre; } };
(2)遞迴解法:簡直是優雅
/** * 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 == nullptr || head->next == nullptr) return head; ListNode* last = reverseList(head->next); head->next->next = head; head->next = nullptr; return last; } };
2.反轉連結串列II:
反轉從位置 m 到 n 的連結串列。請使用一趟掃描完成反轉。
說明:
1 ≤ m ≤ n ≤ 連結串列長度。
(1)遞迴,空間換時間,我佛了。
/** * 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) { //按照題意,時間複雜度為O(n) //可以使用迭代和遞迴兩種方式進行,時間複雜度都是O(n),但是遞迴的空間複雜度為O(n),而迭代為O(1) //遞迴解法 if(m == 1) return reverseN(head, n); head->next = reverseBetween(head->next, m-1, n-1); return head; } ListNode* successor = nullptr; ListNode* reverseN(ListNode* head, int n) { if(n==1) { successor = head->next; return head; } ListNode* last = reverseN(head->next, n-1); head->next->next = head; head->next = successor; return last; }
(2)迭代實現
/** * 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) { //按照題意,時間複雜度為O(n) //可以使用迭代和遞迴兩種方式進行,時間複雜度都是O(n),但是遞迴的空間複雜度為O(n),而迭代為O(1) //迭代解法 ListNode* pCur = head; ListNode* pPre = nullptr; ListNode* pNext = nullptr; ListNode* pPreM = nullptr; ListNode* pM = nullptr; for(int i=0;i<m-1;i++) { pPreM = pCur; pCur = pCur->next; } pM = pCur; for(int j=m;j<=n;j++) { pNext = pCur->next; pCur->next = pPre; pPre = pCur; pCur = pNext; } if(m != 1) { pPreM->next = pPre; } pM->next = pNext; return m==1? pPre : head; } };
3.K個一組反轉連結串列
給你一個連結串列,每 k 個節點一組進行翻轉,請你返回翻轉後的連結串列。
k 是一個正整數,它的值小於或等於連結串列的長度。
如果節點總數不是 k 的整數倍,那麼請將最後剩餘的節點保持原有順序。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* reverseKGroup(ListNode* head, int k) { //先反轉以head開頭的k個元素 //將第k+1個元素作為head遞迴呼叫reverseKGroup函式 //將上述兩個過程的結果連線起來 //base case 如果最後的元素不足k個,就保持不變 if(head == nullptr) return nullptr; ListNode* a = head; ListNode* b = head; for(int i=0;i<k;i++) { if(b == nullptr) return head; b = b->next; } ListNode* newHead = reverse(a,b); a->next = reverseKGroup(b,k); return newHead; } ListNode* reverse(ListNode* a, ListNode* b) { ListNode* pCur = a; ListNode* pPre = nullptr; ListNode* pNext = nullptr; while(pCur != b) { pNext = pCur->next; pCur->next = pPre; pPre = pCur; pCur = pNext; } return pPre; } };