Reverse a linked list from position m to n. Do it in-place and in one-pass.
For example:
Given 1->2->3->4->5->NULL
, m = 2
and n = 4
,
return 1->4->3->2->5->NULL
.
Note:
Given m, n satisfy the following condition:
1 ≤ m ≤ n ≤ length
of list.java
給定一個單鏈表,將第m到第n個之間的元素進行轉。
給定的n和m都是合法的,使用原地方法進行解決(使用常量輔助空間)node
先找到第一個要反轉的元素的前驅(prev),再計算要進行反轉的元素個數,對元素進行頭插法,插在prev後面,同時保持鏈表不斷開。算法
鏈表結點類緩存
public class ListNode { int val; ListNode next; ListNode(int x) { val = x; } }
算法實現類app
public class Solution { public ListNode reverseBetween(ListNode head, int m, int n) { ListNode root = new ListNode(0); ListNode p = root; root.next = head; for (int i = 1; i < m && p != null; i++) { p = p.next; } if (p != null) { ListNode q = p.next; ListNode r; // 若是m爲負數就認爲是從第一個開始交換 if (m < 1) { m = 1; } n = n - m + 1; // n爲要換的結點數目 // 有兩個結點時纔要使用尾插法,尾插的個數爲n-1 for (int i = 1; i < n && q.next != null ; i++) { // 爲要進行尾插的結點 r = q.next; // 在q結點的後面進行尾插操做 q.next = r.next; r.next = p.next; p.next = r; } head = root.next; } return head; } }
問題:this
給一個單向鏈表,把它從頭至尾反轉過來。好比: a -> b -> c ->d 反過來就是 d -> c -> b -> a 。spa
分析:.net
假設每個node的結構是:指針
[java] view plain copycode
由於在對鏈表進行反轉的時候,須要更新每個node的「next」值,可是,在更新 next 的值前,咱們須要保存 next 的值,不然咱們沒法繼續。因此,咱們須要兩個指針分別指向前一個節點和後一個節點,每次作完當前節點「next」值更新後,把兩個節點往下移,直到到達最後節點。
代碼以下:
[java] view plain copy
上面代碼使用的是非遞歸方式,這個問題也能夠經過遞歸的方式解決。代碼以下:
[java] view plain copy
遞歸的方法實際上是很是巧的,它利用遞歸走到鏈表的末端,而後再更新每個node的next 值 (代碼倒數第二句)。 在上面的代碼中, reverseRest 的值沒有改變,爲該鏈表的最後一個node,因此,反轉後,咱們能夠獲得新鏈表的head。
(一)單鏈表的結點結構:
data域:存儲數據元素信息的域稱爲數據域;
next域:存儲直接後繼位置的域稱爲指針域,它是存放結點的直接後繼的地址(位置)的指針域(鏈域)。
data域+ next域:組成數據ai的存儲映射,稱爲結點;
注意:①鏈表經過每一個結點的鏈域將線性表的n個結點按其邏輯順序連接在一塊兒的。
②每一個結點只有一個鏈域的鏈表稱爲單鏈表(Single Linked List)。
所謂的鏈表就好像火車車箱同樣,從火車頭開始,每一節車箱以後都連着後一節車箱。
要實現單鏈表存儲,首先是建立一結點類,其Java代碼以下:
[java] view plain copy
(二)實現反轉的方法:
(1)遞歸反轉法:在反轉當前節點以前先反轉後續節點。這樣從頭結點開始,層層深刻直到尾結點纔開始反轉指針域的指向。簡單的說就是從尾結點開始,逆向反轉各個結點的指針域指向,其過程圖以下所示:
head:是前一結點的指針域(PS:前一結點的指針域指向當前結點)
head.getNext():是當前結點的指針域(PS:當前結點的指針域指向下一結點)
reHead:是反轉後新鏈表的頭結點(即原來單鏈表的尾結點)
Java代碼實現:
[java] view plain copy