實現反轉連結串列--遞迴、迭代、雙指標、棧
描述
2021年,新年第二天,吃過晚飯,沒想到一道簡簡單單的題把我卡了半天,於是乎記錄一下。建議自己先寫寫試試。
題目:
定義一個函式,輸入一個連結串列的頭節點,反轉該連結串列並輸出反轉後連結串列的頭節點。
示例:
輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
連結串列結構:
class ListNode{
int val;
ListNode next;
public ListNode(int val){
this.val = val;
}
}
public ListNode reverseList(ListNode head) {
//實現程式碼
}
其實開始想法是遍歷連結串列,用棧儲存其中的int值,然後再從棧中取出int生成新的連結串列。確實可以實現,但是效率太低,肯定不是最優的。最後再貼出棧的實現方法。
遞迴
相信不少同學和我一樣,遇到遞迴的問題總是很頭疼,而一看解答,卻發現大佬們幾行遞迴程式碼就優雅的解決了問題。遇到遞迴問題很容易進入思維誤區,所謂遞迴,程式反覆呼叫自身即是遞迴。既然能夠呼叫自身說明它每一級的功能都是一樣的,因此我們只需要關注一級遞迴的解決過程即可。
遞迴把握好三個關鍵點就可以了:
- 找整個遞迴的終止條件:遞回應該在什麼時候結束?
- 找返回值:應該給上一級返回什麼資訊?
- 本級遞回應該做什麼:在這一級遞迴中,應該完成什麼任務?
這裡推薦一個部落格,寫的非常清晰,套路解決遞迴問題
對於該題分析:
終止條件:節點為空或者它的下一個節點為空
返回值:返回給上一級已經反轉完成的連結串列
本級應該做什麼:反轉後面的節點,並且將當前節點插入到它後面節點的後面
class Solution {
public ListNode reverseList(ListNode head) {
//終止條件
if(head == null || head.next == null){
return head;
}
//將後面的節點反轉
ListNode next = reverseList(head.next);
//將當前節點插入它後面的節點
head.next.next = head;
//防止產生迴圈連結串列
head.next = null;
return next;
}
}
記得上學時候資料結構老師告訴我們,關於連結串列的操作,一定要在紙上把過程先畫出來,再寫程式。不過這次畫翻車了,這裡記錄下我進入的誤區,因為head.next.next = head這行讓我想了好久,畫圖表示一下當時我的理解:
假設當前傳入的是2節點,假設它後面已經反轉完成,所以畫出了上面的圖,而我一直再想怎麼讓5去指向2,想著想著就迷路了。這裡就是一個思維誤區了,下意識的以為2就是已經指向了5,但是實際應該是下面這樣:
實際上2指向的是3節點,因為2的next並沒有變啊,這樣再看head.next.next = head是不是就瞬間明白了。而head.next = null;也懂了吧,就是防止3指向2,2又指向3。
迭代
一般來說遞迴能夠實現的迭代也可以,可以使用雙指標,也可以使用棧。先說雙指標:
考慮遍歷連結串列,並在訪問各節點時修改 next 引用指向:
class Solution {
public ListNode reverseList(ListNode head) {
//記錄前一個節點用的
ListNode pre = null;
//從頭節點開始
ListNode cur = head;
//臨時記錄下一個節點
ListNode temp = null;
while(cur != null){
//記錄下一個節點
temp = cur.next;
//將當前節點指向上前節點,實現反轉
cur.next = pre;
//將當前節點交給pre,為下一次的迴圈做準備
pre = cur;
//移動到下一個節點
cur = temp;
}
return pre;
}
}
具體思路已經加到註釋上了,不再贅述了,看下時間:
棧是一種先進後出的資料結構,下面是使用棧來實現反轉,思路就是遍歷儲存到棧中,再遍歷棧,生成新的連結串列:
class Solution {
public ListNode reverseList(ListNode head) {
Stack<Integer> stack = new Stack<>();
while(head != null){
stack.add(head.val);
head = head.next;
}
ListNode temp = new ListNode(0),result = temp;
while(stack.size() != 0){
temp.next = new ListNode(stack.pop());
temp = temp.next;
}
return result.next;
}
}
棧沒啥好說的大家隨便看看,果然耗時最長。
記錄完畢。
歲月流逝忽已暮,皆因惆悵不知路。
2021年加油吧,打工人!
相關文章
- Python實現連結串列反轉的方法【迭代法與遞迴法】Python遞迴
- 反轉連結串列系列題練習遞迴遞迴
- java實現連結串列反轉Java
- TypeScript 實現連結串列反轉TypeScript
- C++:用棧實現反轉連結串列,超簡單!C++
- 利用遞迴方法實現連結串列反轉、前N個節點反轉以及中間部分節點反轉遞迴
- 【資料結構】遞迴實現連結串列逆序資料結構遞迴
- 劍指offer面試16 反轉連結串列面試
- 連結串列反轉非遞迴演算法!看不懂打死我!遞迴演算法
- 利用遞迴實現連結串列的排序(歸併排序)遞迴排序
- 實現雙向連結串列
- 反轉連結串列
- 指標和連結串列指標
- 誰說Java無指標, JAVA連結串列指標也好煩 - Java 指標迴歸Java指標
- 棧實現遞迴遞迴
- 【Warrior刷題筆記】劍指offer 6 24 35. 三道題,讓你學會連結串列遞迴迭代輔助棧筆記遞迴
- 連結串列面試題(二)---連結串列逆序(連結串列反轉)面試題
- #反轉連結串列_C++版 #反轉連結串列_Java版 @FDDLCC++Java
- JAVA基礎:語言中連結串列和雙向連結串列的實現(轉)Java
- Go實現雙向連結串列Go
- java實現雙向連結串列Java
- java不用api實現單連結串列反轉(二)JavaAPI
- [Golang]力扣LeetBook—初級演算法—連結串列—迴文連結串列(快慢指標)Golang力扣演算法指標
- 詳細分析連結串列中的遞迴性質(Java 實現)遞迴Java
- 雙向迴圈連結串列基本操作的實現(C語言)C語言
- Java雙向連結串列的實現Java
- c 連結串列之 快慢指標 查詢迴圈節點指標
- JavaScript從反轉陣列到連結串列反轉JavaScript陣列
- C 語言使用非迴圈雙向連結串列實現佇列佇列
- 連結串列-雙向連結串列
- 連結串列-迴圈連結串列
- 資料結構和演算法——Go實現單連結串列並且反轉單連結串列資料結構演算法Go
- Golang從合併連結串列聊遞迴Golang遞迴
- C++實現通用雙向連結串列C++
- 雙向連結串列的功能實現(初版
- 單向迴圈連結串列的實現
- 反轉連結串列、合併連結串列、樹的子結構
- 【LeetCode-連結串列】面試題-反轉連結串列LeetCode面試題