LeetCode 反轉(zhuǎn)鏈表 [簡(jiǎn)單]
反轉(zhuǎn)一個(gè)單鏈表。
來(lái)源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/reverse-linked-list
示例:
輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
進(jìn)階:
你可以迭代或遞歸地反轉(zhuǎn)鏈表。你能否用兩種方法解決這道題?
題目分析:
解法1:
先把 node 中的數(shù)據(jù)取出來(lái)存放到集合中,然后再?gòu)募现腥〕鰯?shù)據(jù),再創(chuàng)建ListNode 放進(jìn)去。這樣使用和額外的空間,肯定不是最優(yōu)解。面試官肯定會(huì)追問(wèn)的。
解法2:
根據(jù)題目的提示,可以使用迭代或者遞歸,那么使用迭代如何實(shí)現(xiàn)呢?
在遍歷鏈表的時(shí)候,將當(dāng)前節(jié)點(diǎn)的next
指向前一個(gè)元素,由于節(jié)點(diǎn)沒(méi)有引用上一個(gè)節(jié)點(diǎn),因此必須事先存儲(chǔ)其前一個(gè)元素,我們可以申請(qǐng)兩個(gè)指針,第一個(gè)指針叫 pre,最初是指向 null 的。每次迭代到 cur,都將 cur 的 next 指向 pre,然后 pre 和 cur 前進(jìn)一位。第二個(gè)指針 cur 指向 head,然后不斷遍歷 cur。都迭代完了(cur 變成 null 了),pre 就是最后一個(gè)節(jié)點(diǎn)了。
圖示解法3:
遞歸的兩個(gè)條件:
終止條件是當(dāng)前節(jié)點(diǎn)或者下一個(gè)節(jié)點(diǎn)==null
在函數(shù)內(nèi)部,改變節(jié)點(diǎn)的指向,也就是 head 的下一個(gè)節(jié)點(diǎn)指向 head 遞歸函數(shù)那句head.next.next = head
很不好理解,其實(shí)就是 head 的下一個(gè)節(jié)點(diǎn)指向head。
遞歸函數(shù)中每次返回的 cur 其實(shí)只最后一個(gè)節(jié)點(diǎn),在遞歸函數(shù)內(nèi)部,改變的是當(dāng)前節(jié)點(diǎn)的指向。
代碼實(shí)現(xiàn)
public class LeetCode_11_ReverseLinkedList {
public static void main(String[] args) {
}
//也可以申請(qǐng)額外的空間 但是肯定不是最優(yōu)解
public ListNode reverseList01(ListNode head) {
if (head == null || head.next == null) {
return head;
}
//這里的 curr 就是最后一個(gè)節(jié)點(diǎn)
ListNode curr = reverseList01(head.next);
//如果鏈表是 1->2->3->4->5,那么此時(shí)的cur就是5
//而head是4,head的下一個(gè)是5,下下一個(gè)是空
//所以head.next.next 就是5->4
head.next.next = head;
//防止鏈表循環(huán),需要將head.next設(shè)置為空
head.next = null;
//每層遞歸函數(shù)都返回cur,也就是最后一個(gè)節(jié)點(diǎn)
return curr;
}
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode curr = head;
ListNode next = null;
while (curr != null) {
//存儲(chǔ)下一個(gè)需要移動(dòng)的指針位置
next = curr.next;
//然后將當(dāng)前節(jié)點(diǎn)指向pre
curr.next = pre;
//新的頭指針向后移動(dòng)
pre = curr;
//頭指針向后移動(dòng)
curr = next;
}
return pre;
}
}