反轉一個單鏈表。
示例:
輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
經典題目。。分別用遞歸和循環實現。
1.循環,比較好理解。
首先定義三個指針代表三個節點(圖第一步)。第一個指針pre,是用於把第二個指針cur指向它(反轉)(圖第二步),第三個指針next,是爲了反轉後,將第二個指針cur往後挪一挪(cur = next),當然同時另外兩個指針都要一起挪一挪。如圖的第三步。
然後注意循環結束條件,我這裏寫的是next != null,但是next == null的時候,情況是這樣子的,如圖
也就是說最後一次循環走不進去,但是還要把最後一個節點反轉一下,所以return前需要 cur.next = pre ,在return cur回去。
代碼:
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null) return null;
ListNode preNode = null;
ListNode curNode = head;
ListNode nextNode = head.next;
while(nextNode != null){
curNode.next = preNode;
preNode = curNode;
curNode = nextNode;
nextNode = nextNode.next;
}
curNode.next = preNode;
return curNode;
}
}
2.遞歸
class Solution {
//代表將一個鏈表反轉,並返回反轉後的頭部。
public ListNode reverseList(ListNode head) {
if(head == null) return null; //輸入爲null的情況
if(head.next == null) return head; //遞歸到最後只有一個節點的情況,將自己返回去,該節點肯定爲 每次遞歸結束後返回的頭節點。
ListNode headNode = reverseList(head.next); //一直遞歸。對應上一行代碼,每次返回的肯定都是同一個頭結點,所以最後返回該節點
ListNode curNode = headNode; //對於每一層遞歸而言,需要將當前的head放到 反轉後的鏈表 的後面,同時把他自己的指向置爲null(ps:看了官方題解後,發現其實就是head.next.next = head(因爲 當前head 其實還指向 反轉後的鏈表 的尾部,只要將他們反指就好了)我是從頭開始遍歷找到最後一個節點,然後將 反轉後的鏈表 的最後一個節點 指向 當前head,可能效率低了一點,)
while(curNode.next != null){
curNode = curNode.next;
} //這幾行 等同於 head.next.next = head,上面有解釋原因。。
curNode.next = head;
head.next = null;
return headNode;
}
}
ps:官方代碼:
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}