题目描述
- 一个数组的maxtree定义如下:
- 数组没有重复元素,包括maxtree在内的每个子树都是根节点最大,而且maxtree是二叉树。
- 给定一个没有重复元素的数组arr,要求生成这个数组对应的maxtree,且时间复杂度和空间复杂度都要求为n。
解题方法1
-
一个数组的matree不是唯一的,但是我们要的是符合时间复杂度和空间复杂度的构建方法。
-
那么如何尽快找到每个数左右两侧第一个比他大的数呢?可以使用栈,如果寻找每个数左边第一个比他大的数,每遍历一个新的数就将它与栈顶比较,小于栈顶入栈,大于栈顶让栈顶出栈直到小于当前栈顶或栈空。
-
如【3 1 2】,遍历到3时栈为空说明3没有左边比他大的数,3入栈,遍历到1时1小于3则1左边第一个比他大的数是3,1入栈。遍历到2时1出栈,2入栈说明2左边第一个大于他的数是3。
-
这样我们就可以以比较低的时间复杂度找到每个元素的左右第一个比他大的数,进而找到每个元素的父节点。
-
然后我们要申请两个哈希表,分别存储每个节点左边第一个大的节点和右边第一个大的节点,key为当前节点,value为当前节点左边第一个大的元素节点或右边。
-
最后利用这两个哈希表遍历所有节点找到当前节点父节点,梳理父子节点映射关系,构建二叉树。
public class Test {
public static void main(String[] args) {
int [] arr = {3,4,5,1,2};
Node root = getmaxtree(arr);
for(Node p=root;p!=null;p=p.left){
System.out.println(p);
}
for(Node p=root;p!=null;p=p.right){
System.out.println(p);
}
}
//传入arr数组,构建maxtree
public static Node getmaxtree(int [] arr){
//先创建所有的节点并存放在一个数组中
Node[] nodes = new Node[arr.length];
for(int i=0;i<arr.length;i++){
nodes[i] = new Node(arr[i]);
}
//创建一个栈用于寻找一个节点的父节点
Stack<Node> s = new Stack<>();
//创建两个哈希表用于存储每个节点左右第一个大于自己的节点
HashMap<Node,Node> mapleft = new HashMap<>();
HashMap<Node,Node> mapright = new HashMap<>();
//遍历node数组,构建哈希表mapleft
for(Node node:nodes){
while(!s.empty() && node.value > s.peek().value){
s.pop();
}
if(s.empty()){
mapleft.put(node,null);
}
else{
mapleft.put(node,s.peek());
}
s.push(node);
}
s.clear(); //构建第一个哈希表后清空栈
//遍历node数组,构建哈希表mapright
for(int i=nodes.length-1;i>=0;i--){
Node node = nodes[i];
while(!s.empty() && node.value > s.peek().value){
s.pop();
}
if(s.empty()){
mapright.put(node,null);
}
else{
mapright.put(node,s.peek());
}
s.push(node);
}
//根据两个哈希表构建二叉树
Node root = null; //记录根节点
for(Node node:nodes){
Node nodeleft = mapleft.get(node); //左第一大
Node noderight = mapright.get(node); //右第一大
Node parent = null; //记录当前节点的父节点
//node为根节点的情况
if(nodeleft==null && noderight==null){
root = node;
}
//noderight为node父节点的一种情况
else if(nodeleft==null){
parent = noderight;
}
//nodeleft为node父节点的一种情况
else if(noderight==null){
parent = nodeleft;
}
else{
parent = nodeleft.value>noderight.value?noderight:nodeleft;
}
//为父子节点建立联系
if(parent!=null){
if(parent.left==null){ //因为父节点可能有两个子节点,要判断一下防止第二个子节点把第一个子节点覆盖了
parent.left = node;
}else{
parent.right = node;
}
}
}
return root;
}
}
class Node{
Node left;
Node right;
Integer value;
Node(int value){
this.value = value;
}
}
来源:CSDN
作者:zuiziyoudexiao
链接:https://blog.csdn.net/zuiziyoudexiao/article/details/104573102