1305. 两棵二叉搜索树中的所有元素
题目:给你 root1
和 root2
这两棵二叉搜索树。请你返回一个列表,其中包含 两棵树 中的所有整数并按 升序 排序。
示例1:
输入:root1 = [2,1,4], root2 = [1,0,3]
输出:[0,1,1,2,3,4]
示例2:
输入:root1 = [0,-10,10], root2 = [5,1,7,0,2]
输出:[-10,0,0,1,2,5,7,10]
示例3:
输入:root1 = [], root2 = [5,1,7,0,2]
输出:[0,1,2,5,7]
示例4:
输入:root1 = [0,-10,10], root2 = []
输出:[-10,0,10]
示例5:
输入:root1 = [0,-10,10], root2 = []
输出:[-10,0,10]
提示:
每棵树最多有 5000 个节点。
每个节点的值在 [-10^5, 10^5] 之间。
解题思路1(已实现):
由于两棵都是二叉搜索树,那么我们可以先把两颗二叉搜索树的结点先按照先序遍历的方法,将遍历的结果逐个放到辅助数组中,得到两个先序排列的数组,然后将两个数组进行一次简单的归并排序便可得到结果。
解题步骤:
- 通过栈
StackRoot
来存放父节点,通过链表num
来存放已排序的子节点; - 循环判断树的节点
root
是否为空,或者判断StackRoot
是否为空;- 若
root
不为空,则说明未找到欲进行遍历的子节点,跳转到3; - 若是
StackRoot
不为空,则说明还有结点未被访问,跳转到4; - 若都不符合则跳转到5;
- 若
- 若是
root
不为空,则将当前的root
节点压进StackRoot
,并继续查找root
的左子树,这步的目的是为了找到先序遍历的节点; - 若是
StackRoot
不为空,则StackRoot.pop()
,并且弹出的节点便是要查找的叶子节点,于是我们将该节点放入num
中,并继续查找其右子树; - 循环判断两个
num
是否为空,若都不为空则跳转到7,否则跳转到6; - 判断两个
num
的第一个元素的大小,将较小的放入结果集result
中,并移除较小的元素,若是num1
先为空,则将num2
剩余的元素依次放入结果集result
中,反之将num1
的放入结果集; - 运行结束,返回结果。
分析思路1的时间复杂度和空间复杂度:
- 遍历了两棵二叉搜索树,时间复杂度为O(n+m),并且最后还要进行遍历两次
num
中的数组,则时间复杂度为O(2n+2m);,即O(n+m) - 由于用
num
分别存放了root
的所有节点,所以空间复杂度为O(n+m);
代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> getAllElements(TreeNode root1, TreeNode root2) {
//链表,存放已搜索到的节点
LinkedList<Integer> num1 = new LinkedList<>();
LinkedList<Integer> num2 = new LinkedList<>();
//栈,存放未被访问的结点
ArrayDeque<TreeNode> StackRoot1 = new ArrayDeque<>();
ArrayDeque<TreeNode> StackRoot2 = new ArrayDeque<>();
//先序遍历二叉搜索树
while (root1 != null || !StackRoot1.isEmpty()) {
if (root1 != null) {
StackRoot1.push(root1);
root1 = root1.left;
} else {
root1 = StackRoot1.pop();
num1.add(root1.val);
root1 = root1.right;
}
}
while (root2 != null || !StackRoot2.isEmpty()) {
if (root2 != null) {
StackRoot2.push(root2);
root2 = root2.left;
} else {
root2 = StackRoot2.pop();
num2.add(root2.val);
root2 = root2.right;
}
}
//存放结果集
List<Integer> result = new ArrayList();
//将两个有序链表进行一趟归并排序
while (num1.size() != 0 || num2.size() != 0) {
//只要两个链表都不为空,则进行比较
if (num1.size() != 0 && num2.size() != 0) {
if (num1.getFirst() <= num2.getFirst()){
result.add(num1.removeFirst());
}
else{
result.add(num2.removeFirst());
}
}
//只要有任意一个链表为空,则将另一个链表依次插入结果集
if (num1.size() != 0 && num2.size() == 0) {
result.add(num1.removeFirst());
}
if((num1.size() == 0 && num2.size() != 0)){
result.add(num2.removeFirst());
}
}
return result;
}
}
提交记录
48 / 48 个通过测试用例
执行用时:26 ms
解题思路2(待实现):
在先序遍历的的时候,每次找到一个子节点便进行比较,将小的结果放入返回的数组,并继续先序遍历小的结果,由于是先序遍历,那么每次比较的元素都将是两棵树中最小子节点,直至两棵树遍历结束便可得到结果。
分析思路2的时间复杂度和空间复杂度:
- 由于只把两棵二叉搜索树遍历一遍,时间复杂度为O(n+m);
- 该过程只有一个存放结果集的数组
result
,所以空间复杂度为O(n+m);
总结:
第一次写关于树的题,虽然是简单的数据结构的题目,但是之前从未在Java中进行过树的操作,导致有很多地方不熟悉,而且在使用集合的时候也不熟练,之后要多多加练习。