[LeetCode] 1305. All Elements in Two Binary Search Trees 兩棵二叉搜尋樹中的所有元素
Given two binary search trees root1
and root2
, return a list containing all the integers from both trees sorted in ascending order.
Example 1:
Input: root1 = [2,1,4], root2 = [1,0,3]
Output: [0,1,1,2,3,4]
Example 2:
Input: root1 = [1,null,8], root2 = [8,1]
Output: [1,1,8,8]
Constraints:
- The number of nodes in each tree is in the range
[0, 5000]
-10^5 <= Node.val <= 10^5
這道題給了兩棵二叉搜尋樹,讓返回一個包含所有結點值的子陣列,並且是有序的。最簡單暴力的方法就是分別遍歷兩棵樹,然後把得到的結點值放到一個數組裡,然後再對該陣列排序,而且也能通過 OJ。用這種方法的話就沒有利用到二叉搜尋樹的性質,用任意一種遍歷順序都可以,參見程式碼如下:
解法一:
class Solution { public: vector<int> getAllElements(TreeNode* root1, TreeNode* root2) { vector<int> res; dfs(root1, res); dfs(root2, res); sort(res.begin(), res.end()); return res; } void dfs(TreeNode* node, vector<int>& res) { if (!node) return; dfs(node->left, res); res.push_back(node->val); dfs(node->right, res); } };
上面的解法並沒有利用到二叉搜尋樹的性質,可能並不是面試官想要看見的解法。二叉搜尋樹具有左子結點值小於父結點值,小於右子結點的特點,所以用中序遍歷得到的結點值是有序的。這裡分別對 root1 和 root2 進行中序遍歷,分別得到兩個有序的陣列,這樣就可以通過 merge 陣列方式來將兩個有序數組合併成一個大的有序陣列了,是線性的複雜度。下面的程式碼用的佇列而不是陣列,並沒有太大的區別,參見程式碼如下:
解法二:
class Solution { public: vector<int> getAllElements(TreeNode* root1, TreeNode* root2) { vector<int> res; queue<int> q1, q2; dfs(root1, q1); dfs(root2, q2); while (!q1.empty() || !q2.empty()) { if (q2.empty() || (!q1.empty() && q1.front() <= q2.front())) { res.push_back(q1.front()); q1.pop(); } else { res.push_back(q2.front()); q2.pop(); } } return res; } void dfs(TreeNode* node, queue<int>& q) { if (!node) return; dfs(node->left, q); q.push(node->val); dfs(node->right, q); } };
之前兩種解法都是遞迴的寫法,再來看一種迭代的寫法,還是用的中序遍歷,不過此時是同時中序遍歷兩棵樹,按照大小順序將結點值加入到結果 res 中,保證了最終的結果是有序的。對於迭代的中序遍歷寫法最好也是要掌握的,需要用到棧來輔助,由於是同時遍歷兩棵樹,所以這裡用兩個棧 st1 和 st2。迴圈到條件是隻要 root1,root2,st1 和 st2 有任意一個不為空,中序遍歷的順序是左根右,所以首先要做的把當前結點下方的所有左子結點壓入棧中,不停的對 root1 遍歷,只要不為空,就將結點壓入棧,然後更新為其左子結點。同理對 root2 進行相同的操作,接下倆判斷若 st2 為空,說明當前要操作 st1 中的結點,或著若 st1 不為空(此時 st2 也不為空),且 st1 的棧頂結點值小於等於 st2 的棧頂結點值時,同樣操作 st1 中的結點。否則操作 st2 中的結點,操作方法都是取出棧頂結點,將其值加入結果 res 中,然後更新為其右子結點即可,參見程式碼如下:
解法三:
class Solution {
public:
vector<int> getAllElements(TreeNode* root1, TreeNode* root2) {
vector<int> res;
stack<TreeNode*> st1, st2;
while (root1 || root2 || !st1.empty() || !st2.empty()) {
while (root1) {
st1.push(root1);
root1 = root1->left;
}
while (root2) {
st2.push(root2);
root2 = root2->left;
}
if (st2.empty() || (!st1.empty() && st1.top()->val <= st2.top()->val)) {
root1 = st1.top(); st1.pop();
res.push_back(root1->val);
root1 = root1->right;
} else {
root2 = st2.top(); st2.pop();
res.push_back(root2->val);
root2 = root2->right;
}
}
return res;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/1305
參考資料:
https://leetcode.com/problems/all-elements-in-two-binary-search-trees/