LeetCode第25題,每K個節點一組進行翻轉,剩下不足K個的保留原狀.java
將鏈表分紅三部分,已翻轉,待翻轉,未翻轉三部分:node
首先,用一個指針t表示要插入的位置的前驅,一邊把head移動k遍,一邊插入在t後面(下圖假設k=3):git
int i=0; for(;i<k && head != null;++i) { temp = head.next; head.next = t.next; t.next = head; head = temp; }
直接插在t的後面,一輪循環以後,移動t與head.github
t的新位置爲未插入head以前的head的位置,所以在插入以前把head的位置保存下來,直接使t移動到該位置,head的位置爲天然移動到的位置,不需改變。算法
ListNode nextTPosition = head; ListNode temp; int i=0; for(;i<k && head != null;++i) { temp = head.next; head.next = t.next; t.next = head; head = temp; } if(i == k) t = nextTPosition;
接着再翻轉,到達7後,7不須要翻轉,由於剩下的節點數不足:ide
這時就須要i發揮做用了,i表示已翻轉的節點的值,由於只是一次遍歷,每遍歷k次便翻轉k次,若i小於k,因爲已經翻轉了剩下的i個節點,所以須要再將這剩下的i個節點翻轉一次:優化
if(i == k) t = nextTPosition; else { for(head = t.next,t.next=null;head!=null;) { temp = head.next; head.next = t.next; t.next = head; head = temp; } break; }
對剩下的i個節點再次翻轉時,不須要修改t的位置,使head指向t.next,再把t.next置爲null,由於此時t爲3d
4->7
若不把t.next置爲null,在指針
head.next = t.next
這一步會使head.next指向錯誤的t.next,致使會在最後一個節點不斷循環。
翻轉最後的i個節點後,跳出循環,返回結果。code
遞歸的話思路也相似,遍歷k次,翻轉k個,若還有須要翻轉的節點,遞歸翻轉,若沒有,翻轉剩下的i個節點。
if(i == k) t.next = reverse(head,k);
大部分代碼與循環相同就不貼了,最大的不一樣是這裏,這裏的t爲原來未遍歷前的head,由於改爲遞歸後,不須要使用t做爲移動的指針指示插入的位置,t.next就至關於翻轉後的最後一個節點,把遞歸的結果插入到這個節點的後面。
由於題目規定只能使用常數的額外空間,所以應該只有這兩種方法了,可是,若是容許使用額外的空間,可使用棧優化直接翻轉的算法。
由於出棧的次序正是翻轉的順序,每遍歷k個節點就壓棧k個節點,若剩餘不足k個節點,把head連上dummy,若還有多餘的節點或者恰好遍歷完,把出棧的節點依次連上主鏈。
while(true) { Stack<ListNode> s = new Stack<>(); ListNode temp = head; int i=0; for(;i<k && head != null;++i) { s.add(new ListNode(head.val)); head = head.next; } if(i == k) { for(i=0;i<k;++i) { t.next = s.pop(); t = t.next; } } else if(head == null) { t.next = temp; break; } }
其中for循環爲遍歷壓棧,i==k判斷是否翻轉鏈表。