題目描述
- 一個數組的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;
}
}