問(wèn)題:Reverse Linked List
Reverse a singly linked list.
Input:
- 鏈表頭結(jié)點(diǎn) :: ListNode
Output:
- 翻轉(zhuǎn)后鏈表頭結(jié)點(diǎn) :: ListNode
Intuition:
這道題是鏈表翻轉(zhuǎn)的最最基本的題型了(沒(méi)有之一)。解法也是非常直接的翻轉(zhuǎn)pointer就好,如果非要說(shuō)tricky的地方就是翻轉(zhuǎn)的時(shí)候注意存儲(chǔ)下之前依賴翻轉(zhuǎn)pointer的其他node。
但是,你敢信我剛開(kāi)始刷題的時(shí)候花了一下午時(shí)間在這道題上,最后還是沒(méi)搞清楚pointer該指哪兒么?是的,對(duì)于這種大部分人認(rèn)為太簡(jiǎn)單了面試不會(huì)考的pointer變換的題目(包括樹(shù)的題型)本渣的水平大概可以形容為左轉(zhuǎn)左轉(zhuǎn)左轉(zhuǎn)左轉(zhuǎn)原來(lái)是個(gè)圈呦(ノへ ̄、)。好了廢話打住,那么現(xiàn)在就來(lái)做個(gè)翻轉(zhuǎn)鏈表的小小歸納。
首先我們需要一個(gè)scanner來(lái)掃描所有的node記為cur。另外還需要cur兩邊的node來(lái)記錄上下關(guān)系,記為pre和next。那么剛開(kāi)始的情況應(yīng)該是這樣的:
之后,很明顯我們需要翻轉(zhuǎn)那個(gè)紅箭頭,但是如果翻轉(zhuǎn)它,那么他原來(lái)指向的node就無(wú)法access了,那就需要一個(gè)變量來(lái)記錄下原來(lái)指向的node,這里用next來(lái)保存。
接下來(lái)翻轉(zhuǎn)箭頭
cur.next = pre
那么這部分就翻轉(zhuǎn)成功了,所有的node指針往后移動(dòng)一位,繼續(xù)下一個(gè)部分的翻轉(zhuǎn):
最后,pre作為新的頭結(jié)點(diǎn)返回。
Code:
public ListNode reverseLL(TreeNode head){
ListNode cur = head;
ListNode pre = null;
ListNode next = null;
while(cur != null){
next = cur.next;
cur.next = pre; //reverse pointer
//move foward to next node
pre = cur;
cur = next;
}
return pre;
}
問(wèn)題:Reverse Linked List II
Reverse a linked list from position m to n. Do it in-place and in one-pass.
Note:
Given m, n satisfy the following condition:
1 ≤ m ≤ n ≤ length of list.
Input:
- 鏈表頭結(jié)點(diǎn) :: ListNode
- 翻轉(zhuǎn)起始位置m :: Integer
- 翻轉(zhuǎn)終了位置n :: Integer
Output:
- 翻轉(zhuǎn)后鏈表頭結(jié)點(diǎn) :: ListNode
Intuition:
剛剛那道題是不是小case呀,那么增加點(diǎn)難度,只翻轉(zhuǎn)第m個(gè)到第n個(gè)節(jié)點(diǎn)的部分。
最直接的想法還是需要三個(gè)指針,cur, pre, next. 但是只有當(dāng)cur到達(dá)起始點(diǎn)時(shí)才開(kāi)始翻轉(zhuǎn),那么很自然的想到需要維持一個(gè)counter。而同樣的翻轉(zhuǎn)停止的部分也需要一個(gè)counter,當(dāng)這個(gè)counter等于m - n的時(shí)候停止翻轉(zhuǎn)。
最后,中間翻轉(zhuǎn)部分結(jié)束后跟原來(lái)鏈表中的起止點(diǎn)相連就可以了.
舉個(gè)??:
m = 2, n = 4, 先找到起始點(diǎn),p在m-1的位置停下,下一個(gè)位置就是pre,依次的cur,next的部分也可以確定,那么我們要翻轉(zhuǎn)的指針就是cur和next之間的那個(gè):
翻轉(zhuǎn)次數(shù)是m-n = 2 次,第一次翻轉(zhuǎn):
第二次翻轉(zhuǎn):
最后接回原來(lái)的起止點(diǎn)
Code:
TC:(n) SC:O(1)
public TreeNode reverseLLII(TreeNode head, int m, int n){
TreeNode dummy = new TreeNode(-1);
dummy.next = head;
//scanner
TreeNode p = dummy;
int cnt1 = 0;
while (cnt1 < m -1){
p = p.next;
cnt1++;
}
//initial pre and cur
ListNode pre = p.next;
ListNode cur = pre.next;
int cnt2 = n - m; //reverse n - m times
while(cnt2 > 0){
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
cnt2--;
}
p.next.next = cur;
p.next = pre;
return dummy.next;
}
再抽象一點(diǎn)點(diǎn),我們?cè)囋嚹懿荒軇?dòng)態(tài)的reverse,也就是每一個(gè)小部分翻轉(zhuǎn)后都立刻與原鏈表鏈接而不是等翻轉(zhuǎn)完全結(jié)束后再連接原來(lái)的鏈表。
首先記錄把pre與右邊界相連,注意這里的右邊界不是指整個(gè)m ~ n的右邊界,而是指最小的翻轉(zhuǎn)section的局部右邊界,比如2 -> 3的局部右邊界就是4.
進(jìn)行翻轉(zhuǎn)
連接好左邊界
繼續(xù)移動(dòng)到下一個(gè)node
code翻轉(zhuǎn)改動(dòng)的部分是:
ListNode pre = p.next; //leftBound.next
ListNode cur = pre.next;
while(cnt2 > 0){
pre.next = cur.next;
cur.next = p.next;
p.next = cur;
cur = pre.next;
cnt2--;
}
問(wèn)題:Reverse Nodes in k-Group
Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
You may not alter the values in the nodes, only nodes itself may be changed.
Only constant memory is allowed.
Input:
- 鏈表頭結(jié)點(diǎn) :: ListNode
- 翻轉(zhuǎn)間隔k :: Integer
Output:
- 翻轉(zhuǎn)后鏈表頭結(jié)點(diǎn) :: ListNode
Intuition:
挑戰(zhàn)下極限吧,這道題應(yīng)該是我見(jiàn)過(guò)鏈表翻轉(zhuǎn)最高難度的代表啦,弄懂這道題,鏈表翻轉(zhuǎn)應(yīng)該就沒(méi)多大問(wèn)題了。
還是借助之前兩題的思想counter和in place翻轉(zhuǎn)。不同的是counter指示的時(shí)機(jī)是什么?每遇到某幾個(gè)數(shù)就去做某某事,這個(gè)條件實(shí)現(xiàn)最簡(jiǎn)單的方法是什么?mod對(duì)不對(duì)~ 嗯,大功告成,我們要改善的其實(shí)就是這么一點(diǎn)點(diǎn)。
Code:
TC:(n) SC:O(1)
public ListNode reverseK(TreeNode head, int k){
if (head == null || k == 1){
return head;
}
ListNode p = head;
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode leftbound = dummy;
int cnt = 0;
while(p != null){
cnt++;
if(cnt % k == 0){//find reverse section
ListNode pre = helper(leftBound, p.next);
p = pre.next;
}else{
p = p.next;
}
}
return
}
public ListNode helper(ListNode leftBound, ListNode rightBound){
ListNode pre = leftBound.next;
ListNode cur = pre.next;
while(cur != rightBound){
pre.next = cur.next;
cur.next = leftBound.next;
leftBound.next = cur;
cur = pre.next;
}
return pre;
}
Reference
https://leetcode.com/problems/reverse-linked-list/description/
https://leetcode.com/problems/reverse-linked-list-ii/description/
https://leetcode.com/problems/reverse-nodes-in-k-group/description/
https://discuss.leetcode.com/topic/12364/non-recursive-java-solution-and-idea/2