前言
以專題的形式更新刷題貼,歡迎跟我一起學習刷題,相信我,你的堅持,絕對會有意想不到的收穫。每道題會提供簡單的解答,如果你有更優雅的做法,歡迎提供指點,謝謝。
注:如果程式碼排版出現了問題麻煩通知我下,謝謝。
【題目描述】
對於二叉樹的節點來說,有本身的值域,有指向左孩子和右孩子的兩個指標;對雙向連結串列的節點來說,有本身的值域,有指向上一個節點和下一個節點的指標。在結構上,兩種結構有相似性,現有一棵搜尋二叉樹,請將其轉為成一個有序的雙向連結串列。
節點定義:
class Node2{
public int value;
public Node2 left;
public Node2 right;
public Node2(int value) {
this.value = value;
}
}
例如:
這棵二查搜尋樹轉換後的雙向連結串列從頭到尾依次是 1~9。對於每一個節點來說,原來的 right 指標等價於轉換後的 next 指標,原來的 left 指標等價於轉換後的 last 指標,最後返回轉換後的雙向連結串列的頭節點。
【要求】
如果連結串列的長度為 N, 時間複雜度達到 O(N)。
【難度】
尉:★★☆☆
【解答】
方法一:採用佇列輔助
如果用一個佇列來輔助的話,還是挺容易。採用中序遍歷的方法,把二叉樹的節點全部放進佇列,之後在逐一彈出來連線成雙向連結串列。
程式碼如下
public static Node2 convert1(Node2 head) {
Queue<Node2> queue = new LinkedList<>();
//將節點按中序遍歷放進佇列裡
inOrderToQueue(head, queue);
head = queue.poll();
Node2 pre = head;
pre.left = null;
Node2 cur = null;
while (!queue.isEmpty()) {
cur = queue.poll();
pre.right = cur;
cur.left = pre;
pre = cur;
}
pre.right = null;
return head;
}
private static void inOrderToQueue(Node2 head, Queue<Node2> queue) {
if (head == null) {
return;
}
inOrderToQueue(head.left, queue);
queue.offer(head);
inOrderToQueue(head.right, queue);
}
這種方法的時間複雜度為 O(n), 空間複雜度也為 O(n)。
方法2:通過遞迴的方式
在之前打卡的9道題中,幾乎超過一般都用到了遞迴,如果這些題目使用的遞迴大家都理解了,並且能夠自己獨立寫出程式碼了,那麼我相信大家對遞迴的思想、使用已經有一定的熟練性。
我們假設函式conver的功能就是把二叉樹變成雙向連結串列,例如對於這種一棵二叉樹:
經過conver轉換後變成這樣:
注意,轉換之後,把最右邊節點的right指標指向了最左邊的節點的。
對於下面這樣一顆二叉樹:
採用conver函式分別對左右子樹做處理,結果如下:
之後,再把他們連線起來
瞭解了基本原理之後,直接看程式碼吧。
public static Node2 conver(Node2 head) {
if (head == null) {
return head;
}
Node2 leftE = conver(head.left);
Node2 rightE = conver(head.right);
Node2 leftB = leftE != null ? leftE.right : null;
Node2 rightB = rightE != null ? rightE.right : null;
if (leftE != null && rightE != null) {
leftE.right = head;
head.left = leftE;
head.right = rightB;
rightB.left = head;
rightE.right = leftB;
return rightE;
} else if (leftE != null) {
leftE.right = head;
head.left = leftE;
head.right = leftB;
return head;
} else if (rightE != null) {
head.right = rightB;
rightB.left = head;
rightE.right = head;
return rightE;
} else {
head.right = head;
return head;
}
}
時間複雜度為O(n),空間複雜度為O(h),其中h是二叉樹的高度。
原理雖然不難,但寫起程式碼,還是有挺多細節需要注意的,所以一直強調,有時間的話,一定要自己手打一遍程式碼,有時你以為自己懂了,可能在寫程式碼的時候,發現自己並沒有懂,一寫就出現很多bug。
【連結串列問題】打卡7:將單向連結串列按某值劃分成左邊小,中間相等,右邊大的形式
最後推廣下我的公眾號:苦逼的碼農,文章都會首發於我的公眾號,期待各路英雄的關注交流。