題目
給出一個鏈表,每 k 個節點一組進行翻轉,并返回翻轉后的鏈表。
k 是一個正整數,它的值小于或等于鏈表的長度。如果節點總數不是 k 的整數倍,那么將最后剩余節點保持原有順序。
示例 :
給定這個鏈表:1->2->3->4->5
當 k = 2 時,應當返回: 2->1->4->3->5
當 k = 3 時,應當返回: 3->2->1->4->5
說明 :
你的算法只能使用常數的額外空間。
你不能只是單純的改變節點內部的值,而是需要實際的進行節點交換。
思路
題目的難度在于翻轉的長度不再是整個鏈表的長度了。在確定反轉長度的情況下仍然可以利用鏈表的reverse,用1-2-3-4-5為例,首先反轉兩個變成2-1-3-4-5,下一次應該反轉3和4,利用reverse仍然可以實現,但要注意的是,反轉后的順序4-3,其中的4必須與前面1聯系,而3必須與后面的3聯系,否則整個鏈表就斷了。另外,最后只剩下一個5時,其長度已經小于要求的長度2了,這時候應該返回NULL,代表與前面的關系不改變。
首先給出改進的reverse函數,其中head表示當前要反轉的鏈表段的起始位置,n-1表示還剩有多少個數沒有完成反轉,tail表示這段要反轉鏈表反轉后的尾部(其實就是反轉前此段鏈表的頭部),begin表示此段鏈表的前一個結點,在完成反轉后必須與前一個結點保持聯系。
ListNode* reverse (ListNode* head, int n, ListNode* tail , ListNode* begin)
{
if (head && !head->next && n > 1) return NULL;
if (n == 1)
{
if (head && tail)
{
tail->next = head->next;
}
if (begin)
{
begin->next = head;
}
}
else if (head && head->next && n > 1)
{
ListNode* temp = reverse(head->next, n - 1, tail, begin);
if (temp)
{
temp->next = head;
}
if (!temp)
{
return NULL;
}
}
return head;
}
下面給出調用reverse的代碼,首先應該獲得第一段反轉,如果反轉的結果是NULL,說明整個鏈表的長度都不夠,則直接返回原鏈表即可。否則的話,就找到新鏈表開始的位置,保存下來,作為最后返回時用。完成第一段反轉后,下一段反轉的起始應為第一段的末尾的下一個結點,然后繼續reverse就ok了。
ListNode* reverseKGroup2(ListNode* head, int k)
{
ListNode* result = head;
int t = k;
while (t > 1 && result)
{
result = result->next;
t--;
}
ListNode* temp = reverse(head, k, head, NULL);
if (!temp) return head;
while (temp && temp->next)
{
temp = reverse(temp->next, k, temp->next, temp);
}
return result;
}