25. Reverse Nodes in k-Group[H]k個一組翻轉鏈表

題目


Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
Example:
  Given this linked list: 1->2->3->4->5
  For k = 2, you should return: 2->1->4->3->5
  For k = 3, you should return: 3->2->1->4->5
Note:html

  • Only constant extra memory is allowed.
  • You may not alter the values in the list's nodes, only nodes itself may be changed.

思路


先分析題目的幾個要求:node

  • 每k個節點一組進行翻轉,返回翻轉以後的鏈表
  • 若是節點總數不是k的整數倍,則剩餘節點保留原有順序
  • 只能使用常數的額外空間
  • 不能只是單純改變節點的內部值,而是對節點進行交換

分析可知,題目要求實現兩個功能,一個是如何實現每k個節點一組;一個是翻轉節點。python

  • 每k個節點分組
    • 循環:定義一個變量count記錄走過的節點長度。若是count是k的整數倍,就進行翻轉;若是不是,繼續遍歷節點。
    • 遞歸:分別定義節點1(用於記錄每一個分組結束位置的下一個節點)和節點2(每一個分組的第一個節點),遞歸將節點2到節點1之間的節點翻轉。
  • 翻轉節點
    • 頭插法
    • 記錄節點法

這兩個功能所用的方法能夠自由組合。less

思路1:頭插法+遞歸

分組用遞歸完成:
定義節點lCur記錄分組結束位置的下一個節點,經過k循環來找到每一個lCur;利用節點head記錄每一個分組的開始位置。翻轉從headlCur之間的節點,完成一組節點的翻轉,獲得一組新的節點lHead。此時節點head已經到了分組的最後一位,從後面接上遞歸調用下一分組獲得的新節點lHead,並返回新節點。
翻轉用頭插法完成(實現方法見Tips):
頭插法以鏈表1->2->3->4->5爲例子,假設k=5,完成以下圖過程:
this

思路2:記錄節點法+循環

分組用循環完成,翻轉用記錄節點完成(實現方法見Tips)。
以鏈表1->2->3->4->5爲例子,假設k=4,完成以下過程:
2->1->3->4->5
3->2->1->4->5
4->3->2->1->5
如上是4個一組的節點翻轉,每行表明一次循環。code

Tips

節點的翻轉有兩種方法htm

(1)頭插法

新建一個虛擬節點dummy,並保證虛擬節點鏈接鏈表的頭節點。每當遍歷到一個節點時,就把它鏈接到虛擬節點的下一個節點(整個鏈表的頭部)。定義pCur爲當前要翻轉的節點,過程以下:blog

//Step1:新建一個節點記錄下一個要翻轉的節點
ListNode* pNext = pCur->next;
 //Step2:將pCur置於整個節點的頭部(即已經翻轉好的節點的頭部,完成翻轉)
pCur->next = dummy->next;
//Step1:更新虛擬節點dummy的指向,使其指向鏈表的頭節點
dummy->next = pCur;
//Step4:更新當前節點,將其置於下一個要翻轉的節點
pCur = pNext;

翻轉的過程如圖所示(以要翻轉的節點的值爲3爲例):
遞歸

(2)記錄節點法

pCur表示當前要翻轉的節點,pPre表示當前要翻轉的前一個節點(也是已經完成翻轉操做的最後一個節點),一次翻轉過程(一次循環)以下:ip

// Step1:pPre鏈接下一個要翻轉的節點
pPre->next = pCur->next;
// Step2:pCur節點鏈接已經翻轉好的節點(翻轉當前節點)
pCur->next = dummy->next;
// Step3:更改虛擬節點的鏈接,使它指向已經翻轉好的節點
dummy->next = pCur;
// Step4:pCur指向下一個要翻轉的節點
pCur = pPre->next;

翻轉的過程如圖2所示:

圖2:記錄節點翻轉圖解
#C++
  • 思路1
/**
 * 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) {
        
        ListNode* lCur =head; //該節點用於記錄每組節點結束後的下一個節點
        
        //循環找到每組結束的下一個節點
        for(int i= 0 ; i < k; i++){
            if(lCur == nullptr)
                return head;
            lCur = lCur->next;
        }
        
        ListNode* lHead = reverseOneGroup(head,lCur); 
        head->next = reverseKGroup(lCur, k);
        return lHead;
    }
    
    /**
     * @Description:頭插法實現一組節點內的翻轉
     * lHead:當前一組節點的頭節點
     * lTail:當前一組節點結束位置的下一個節點
     */
    ListNode* reverseOneGroup(ListNode* lHead, ListNode* lTail){
        ListNode* dummy = new ListNode(-1);
        ListNode* lCur = lHead;
        while(lCur != lTail){
            ListNode* lNext = lCur->next;
            lCur->next = dummy->next;
            dummy->next = lCur;
            lCur = lNext;
        }
        return dummy->next;
    }
};
  • 思路2
/**
 * 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 == nullptr || k ==1)
            return head;
        
        //輔助的虛擬節點
        ListNode* dummy = new ListNode(-1);
        //當前節點的上一個節點
        ListNode* lPre = dummy;
        //當前節點
        ListNode* lCur = head;
        
        dummy->next = head;
        
        int count = 0; //記錄長度
        while(lCur != nullptr){
            count ++;
            if(count % k ==0){
                lPre = reverseOneGroup(lPre, lCur->next);
                lCur = lPre->next;
            }
            else{
                lCur = lCur->next;
            }
        }
        return dummy->next;
    }
    
    /**
     * @Description:記錄節點法實現一組節點內的翻轉
     * lPre:當前一組節點的上一個節點
     * lNext:當前一組節點的下一個節點
     */
    ListNode* reverseOneGroup(ListNode* lPre, ListNode* lNext){
        ListNode* lEnd = lPre->next;
        ListNode* lCur = lEnd->next;
        while(lCur != lNext){
            lEnd->next = lCur->next;
            lCur->next = lPre->next;
            lPre->next = lCur;
            lCur = lEnd->next;
        }
        return lEnd;
    }
};

Python

參考

[1] https://www.cnblogs.com/byrhuangqiang/p/4311336.html
[2] https://www.cnblogs.com/grandyang/p/4441324.html

相關文章
相關標籤/搜索