构造数组的MaxTree

要求:给定一个无序的,无重复元素的数组,生成MaxTree,要求每一个根节点处为当前最大值

           时间复杂度要求O(n),空间复杂度O(n)

思路:一开始第一个想法是排序,在生成二叉排序树之类的,堆排序递归之类的,但是题目要求了时间复杂度为O(n),这些方 法都超了。但是题目没有要求生成的MaxTree一定为完全二叉树之类的,只要符合根节点最大,所以,我们可以自己规定MaxTree的特点。(书上P23页开始),证明了除全局最大的根节点有两个子树,其他根节点全是单边的。最后生成的树感觉是只有两条腿。。。。。

e.g.[3,4,5,1,2]

           5

         /   \

     4       2

  /        /

3        1

这样就会出现一个规则,一个节点的位置与它在数组中左右相邻的最大值有关。具体见书23页。。。。

※※※  关于记录两边的相邻最大值。可以用stack结构辅助。例如【3,1,2】,首先压入3,再看1,比3小,继续压入。再看2,比1大,说明2的左侧相邻最大值在1的下面,首先记录map(1,3),说明1的左侧最大值确定了是3,记录好之后弹出1,剩下3,3比2大,OK,直接压入2。 最后栈中的顺序为【3,2】,再依次pop出来,生成map对。

public TreeNode getMaxTree(int[] arr) {
    	TreeNode[] narr = new TreeNode[arr.length];
    	for(int i=0; i<arr.length;i++) {
    		narr[i] = new TreeNode(arr[i]);
    	}
    	Stack<TreeNode> stack = new Stack<TreeNode>();    //用stack栈结构来寻找相邻的最大值。
    	HashMap<TreeNode,TreeNode> left = new HashMap<TreeNode,TreeNode>();   //用两个map来分别存储每一个节点的左大,右大
    	HashMap<TreeNode,TreeNode> right = new HashMap<TreeNode,TreeNode>();   //注意存的都为节点本身,没有比他大的酒味null
    	//////////////////记左边最大/////////////////////
    	for(int i=0;i!=narr.length;i++) {    //先从左到右记一遍,左侧相邻最大的,生成一个leftMap
    		TreeNode cur = narr[i];
    		while(!stack.isEmpty()&&stack.peek().value<cur.value) {    //若此时的值比栈顶大,首先记录栈顶元素下面的最大值,再弹出它,把当前值压入。
    			popStackSetMap(stack,left);     //中间逆序的单独记
    		}
    		stack.push(cur);       //正常的顺序直接压进去
    	}
    	while(!stack.isEmpty()) {          //最后再记一遍顺序正确的
    		popStackSetMap(stack,left);
    	}
    	////////////////////记右边最大/////////////////
    	for(int i = narr.length;i>=0;i--) {    //再从右到左记一遍,记右侧相邻大的,生成一个rightMap
    		TreeNode cur = narr[i];
    		while(!stack.isEmpty()&&stack.peek().value<cur.value) {
    			popStackSetMap(stack,right);    //中间逆序单独计
    		}
    		stack.push(cur);      //正常的顺序直接压进去
    	}
    	while(!stack.isEmpty()) {     
    		popStackSetMap(stack,right);      //最后再记一遍顺序正确的元素
    	}
    	/////////////////开始生成树//////////////////
    	TreeNode head = null;
    	for(int i=0;i<narr.length;i++) {
    		TreeNode cur = narr[i];       //分别取出当前节点的左,右最大值(存的是节点)
    		TreeNode leftNode = left.get(cur);
    		TreeNode rightNode = right.get(cur);
    		//根据左右最大值的情况来进行判断
    		if(left==null&&right==null) {    //若左,右都没有比它还大的,那么它就是最大值,为根节点
    			head = cur;
    		}else if(leftNode==null){       //只有右侧有  4
    			if(rightNode.left==null) {
    				rightNode = cur;
    			}else {
    				rightNode.right = cur;
    			}
    		}else if(right==null) {         //只有左侧有 2
    			if(leftNode.left==null) {
    				leftNode.left = cur;
    			}else {
    				leftNode.right = cur;
    			} 
    		}else {                          //两侧都有 1
    			TreeNode parent = leftNode.value<right.value?leftNode:rightNode;
    			if(parent.left==null) {
    				parent.left = cur;
    			}else {
    				parent.right = cur;
    			}
    		}
    	}
    	return head;
    }
	
	public void popStackSetMap(Stack<TreeNode> stack,HashMap<TreeNode,TreeNode> map) {
		TreeNode popNode = stack.pop();         //弹出元素
		if(stack.isEmpty()) {                   //生成map的函数
			map.put(popNode, null);
		}else {
			map.put(popNode, stack.peek());
		}
	}

点赞