level:hard
題目:二叉搜尋樹中的兩個節點被錯誤地交換。
請在不改變其結構的情況下,恢復這棵樹。
示例 :
高階:♦ 使用 o(n) 空間複雜度的解法很容易實現。
♦ 你能想出乙個只使用常數空間的解決方案嗎?
思路:要充分利用二叉搜尋樹的特性。二叉搜尋樹的中序遍歷得到的序列是遞增。 假設遞增序列 a=[
1,2,
3,4,
5,6,
7]a=[1,2,3,4,5,6,7]
a=[1,2
,3,4
,5,6
,7]變成了 a=[
1,6,
3,4,
5,2,
7]a=[1,6,3,4,5,2,7]
a=[1,6
,3,4
,5,2
,7],顯然可以發現有兩個位置不滿足ai+1
a_i < a_ai
+1。因此本題的任務就是需要找到這兩個位置並交換即可。
中序遍歷二叉樹搜尋樹
找到不滿足條件的位置
遍歷後的遞增數列中,如果是相鄰的兩個數交換,那麼僅有乙個位置不滿足條件,否則有兩個。如果有乙個,標記為 i
ii ,那麼對應被錯誤交換的結點是 a
ia_i
ai 和 ai+
1a_ai+1。
如果是有兩個結點不滿足條件,標記為 i
ii 和 j
jj(i
i<
j 且a
i>ai
+1a_i > a_
ai>ai
+1 && a
j>aj
+1a_j > a_
aj>aj
+1),那麼對應被錯誤交換的結點是 a
ia_i
ai 和 aj+
1a_aj+1。
交換找到的兩個待交換的結點即可
開闢乙個新陣列 num
snums
nums
來記錄中序遍歷得到的值序列,然後線性遍歷找到兩個位置 i
ii 和 j
jj,並重新遍歷原二叉搜尋樹修改對應節點的值完成修復,具體實現可以看下面的**。
**:
/**
* definition for a binary tree node.
* public class treenode
* treenode(int val)
* treenode(int val, treenode left, treenode right)
* }*/class
solution
// 遞迴中序遍歷二叉搜尋樹
public
void
inorder
(treenode root, list
nums)
public
int[
](list
nums)
else}}
return
newint
;}public
void
recover
(treenode root,
int count,
int x,
int y)
recover
(root.right, count, x, y)
;recover
(root.left, count, x, y);}
}}複雜度分析
時間複雜度:o(n
)o(n)
o(n)
,其中 n
nn 為二叉搜尋樹的節點數。中序遍歷需要 o(n
)o(n)
o(n)
的時間,判斷兩個交換節點在最好的情況下是 o(1
)o(1)
o(1)
,在最壞的情況下是 o(n
)o(n)
o(n)
,因此總時間複雜度為 o(n
)o(n)
o(n)
。空間複雜度:o(n
)o(n)
o(n)
。我們需要用 num
snums
nums
陣列儲存樹的中序遍歷列表。
每日一題 LeetCode
在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數。示例 1 輸入 7,5,6,4 輸出 5 限制 0 陣列長度 50000 思想是 分治演算法 所有的 逆序對 於 3 個部分 左邊區間的逆序對 右邊區間的逆序對 橫跨兩個區間的...
LeetCode每日一題(題1028)
最近在刷leetcode每日一題,每次做完之後總能有些收穫,所以想著不如每天寫個部落格記錄一下做的題目的解法以及自己寫的時候問題出在 從先序遍歷還原二叉樹 題目大意 給出乙個字串 1 2 3 4 5 6 7 1代表節點的值,前面的 個數代表節點的深度。如果只有乙個子節點,保證這個節點為左子節點。返回...
LeetCode每日一題(題139)
題目 題目大意 給出乙個字串s和乙個字串陣列words,判斷s是否能夠拆分成多個words中的字串。分析 這道題比較簡單的方式應該是採用動態規劃來做。對於任意乙個字串中的區間,可以判斷該區間組成的字串是否在字典中,如果是,則這個區間的真假取決於前面那個區間的真假。給出狀態轉移方程dp i dp j ...