LeetCode(15): 每k個一組翻轉鏈表


hard!

題目描述:

給出一個鏈表,每 個節點為一組進行翻轉,並返回翻轉后的鏈表。

是一個正整數,它的值小於或等於鏈表的長度。如果節點總數不是 的整數倍,那么將最后剩余節點保持原有順序。

示例 :

給定這個鏈表:1->2->3->4->5

當 = 2 時,應當返回: 2->1->4->3->5

當 = 3 時,應當返回: 3->2->1->4->5

說明 :

  • 你的算法只能使用常數的額外空間。
  • 你不能只是單純的改變節點內部的值,而是需要實際的進行節點交換。

解題思路:

這道題讓我們以每k個為一組來翻轉鏈表,實際上是把原鏈表分成若干小段,然后分別對其進行翻轉,那么肯定總共需要兩個函數,一個是用來分段的,一個是用來翻轉的,我們就以題目中給的例子來看,對於給定鏈表1->2->3->4->5,一般在處理鏈表問題時,我們大多時候都會在開頭再加一個dummy node,因為翻轉鏈表時頭結點可能會變化,為了記錄當前最新的頭結點的位置而引入dummy node,那么我們加入dummy node后的鏈表變為-1->1->2->3->4->5,如果k為3的話,我們的目標是將1,2,3翻轉一下,那么我們需要一些指針,pre和next分別指向要翻轉的鏈表的前后的位置,然后翻轉后pre的位置更新到如下新的位置:

-1->1->2->3->4->5
 |           |
pre         next

-1->3->2->1->4->5
          |  |
         pre next

以此類推,只要next走過k個節點,就可以調用翻轉函數來進行局部翻轉了。

C++解法一:

 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode(int x) : val(x), next(NULL) {}
 7  * };
 8  */
 9 class Solution {
10 public:
11     ListNode *reverseKGroup(ListNode *head, int k) {
12         if (!head || k == 1) return head;
13         ListNode *dummy = new ListNode(-1);
14         ListNode *pre = dummy, *cur = head;
15         dummy->next = head;
16         int i = 0;
17         while (cur) {
18             ++i;
19             if (i % k == 0) {
20                 pre = reverseOneGroup(pre, cur->next);
21                 cur = pre->next;
22             } else {
23                 cur = cur->next;
24             }
25         }
26         return dummy->next;
27     }
28     ListNode *reverseOneGroup(ListNode *pre, ListNode *next) {
29         ListNode *last = pre->next;
30         ListNode *cur = last->next;
31         while(cur != next) {
32             last->next = cur->next;
33             cur->next = pre->next;
34             pre->next = cur;
35             cur = last->next;
36         }
37         return last;
38     }
39 };

也可以在一個函數中完成,我們首先遍歷整個鏈表,統計出鏈表的長度,然后如果長度大於等於k,我們開始交換節點,當k=2時,每段我們只需要交換一次,當k=3時,每段需要交換兩次,所以i從1開始循環,注意交換一段后更新pre指針,然后num自減k,直到num<k時循環結束。

C++解法二:

 1 class Solution {
 2 public:
 3     ListNode* reverseKGroup(ListNode* head, int k) {
 4         ListNode *dummy = new ListNode(-1), *pre = dummy, *cur = pre;
 5         dummy->next = head;
 6         int num = 0;
 7         while (cur = cur->next) ++num;
 8         while (num >= k) {
 9             cur = pre->next;
10             for (int i = 1; i < k; ++i) {
11                 ListNode *t = cur->next;
12                 cur->next = t->next;
13                 t->next = pre->next;
14                 pre->next = t;
15             }
16             pre = cur;
17             num -= k;
18         }
19         return dummy->next;
20     }
21 };

也可以使用遞歸來做,我們用head記錄每段的開始位置,cur記錄結束位置的下一個節點,然后我們調用reverse函數來將這段翻轉,然后得到一個new_head,原來的head就變成了末尾,這時候后面接上遞歸調用下一段得到的新節點,返回new_head即可。

C++解法三:

 1 class Solution {
 2 public:
 3     ListNode* reverseKGroup(ListNode* head, int k) {
 4         ListNode *cur = head;
 5         for (int i = 0; i < k; ++i) {
 6             if (!cur) return head;
 7             cur = cur->next;
 8         }
 9         ListNode *new_head = reverse(head, cur);
10         head->next = reverseKGroup(cur, k);
11         return new_head;
12     }
13     ListNode* reverse(ListNode* head, ListNode* tail) {
14         ListNode *pre = tail;
15         while (head != tail) {
16             ListNode *t = head->next;
17             head->next = pre;
18             pre = head;
19             head = t;
20         }
21         return pre;
22     }
23 };

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM