刷题日志(7)——二叉树高频习题(下)
文章目录
- 一. 二叉树遍历的非递归实现
- 1.先序非递归实现
- 2.中序非递归实现
- 3.后序非递归实现
- 二、验证二叉树性质
- 1.验证平衡二叉树
- 2.验证二叉搜索树
- 3.验证完全二叉树
- 三. 完全二叉树的节点个数(时间复杂度低于O(n))
一. 二叉树遍历的非递归实现
1.先序非递归实现
//思路: 使用栈模拟递归过程
// 先序: 根 左 右 ,为了先打印左再打印右,则需要右节点先入栈
public static void preOrder(TreeNode root) {Stack<TreeNode> s=new Stack<>();s.add(root);while(!s.isEmpty()) {//对头出队列TreeNode cur=s.pop();System.out.print(cur.val+" ");//先入右,再入左if(cur.right!=null) {s.add(cur.right);}if(cur.left!=null) {s.add(cur.left);}}
}
2.中序非递归实现
public static void inOrder(TreeNode root) {if(root!=null) {Stack<TreeNode> s=new Stack<>();//只要栈不为空或者root不为空,就不停止while(!s.isEmpty()||root!=null) {//只要节点root存在左孩子,就一直遍历左孩子if(root!=null) {s.push(root); //遍历过程加入栈中root=root.left; //到下一个左孩子}//如果root为空,即此时左孩子为空,则处理中间节点对头else {TreeNode cur=s.pop(); //队头出队System.out.print(cur.val+" ");root=cur.right; //处理右孩子,右孩子重复左孩子的逻辑}}}
}
3.后序非递归实现
public static void posOrder(TreeNode root) {if(root!=null) {Stack<TreeNode> stack=new Stack<>();Stack<TreeNode> collect=new Stack<>();stack.push(root);while(!stack.isEmpty()) {root=stack.pop();collect.push(root);if(root.left!=null) {stack.push(root.left);}if(root.right!=null) {stack.push(root.right);} }while(!collect.isEmpty()) {System.out.print(collect.pop().val+" ");}}
}
//实际上一个栈也可以实现: https://www.bilibili.com/video/BV1194y16727
二、验证二叉树性质
1.验证平衡二叉树
//思路: 以二叉树的最大深为基础,设置标记位,表示是否为平衡二叉树,
// 递归求左右子树高度的同时计算高度差,只有abs(差值)>1就修改标记为,且只能true->false
//时间复杂度: O(n)
public class BlanceTree {
public static boolean blance;public int height(TreeNode root) {if(root==null) return 0;int lh=height(root.left); //左树高int rh=height(root.right);//右树高if(Math.abs(lh-rh)>1) { //计算高度差blance=false;}return 1+Math.max(lh,rh);
}
public boolean isBalanced(TreeNode root) {blance=true; //由于blance为静态成员,因此每次都要置为初始值height(root);return blance;
}
2.验证二叉搜索树
//详细解释: https://www.bilibili.com/video/BV1194y16727public static long min,max; //记录当前树cur的最小,最大值public boolean isValidBST(TreeNode root) {if(root==null) {//这样设置为了避免空节点的影响,使lmax<val<rminmin=Long.MAX_VALUE;max=Long.MIN_VALUE;}boolean lok=isValidBST(root.left); //左子树是否为搜索树//拿到左子树的最大,最小值long lmin=min;long lmax=max;boolean rok=isValidBST(root.right);//右子树是否为搜索树//拿到右子树的最大最小值long rmin=min;long rmax=max;//更新全局最小,最大值min=Math.min(Math.min(lmin,rmin),root.val); max=Math.max(Math.max(lmax,rmax),root.val);return lok&&rok&&lmax<root.val&&rmin>root.val;}
3.验证完全二叉树
//方法一: 节点编号
public static int MAXN=101;
public static TreeNode[] queue=new TreeNode[MAXN];
//记录节点编号的数组
public static int[] pos=new int[MAXN];
public static int l,r;//树的一个特性: 编号,知道1个编号就可以指定孩子的编号 =》 只要编号不连续就不是完全二叉树
public boolean isCompleteTree3(TreeNode root) {l=r=0;queue[r]=root;pos[r++]=1;int prevIndex=0;while(l<r) {TreeNode cur=queue[l];int index=pos[l++];if(index!=prevIndex+1) {return false;}prevIndex=index;if(cur.left!=null) {queue[r]=cur.left;pos[r++]=2*index;}if(cur.right!=null) {queue[r]=cur.right;pos[r++]=2*index+1;}}return true;
}//方法二:
//数组模型队列
public boolean isCompleteTree2(TreeNode root) {l=r=0;boolean leaf=false;queue[r++]=root;while(l<r) {TreeNode cur=queue[l++];//不是完全二叉树的情况:// 1.左孩子为空,但右孩子不为空 2.左空右不空,后面节点一定要是叶子节点if((cur.left==null&&cur.right!=null)||(leaf&&(cur.left!=null||cur.right!=null))) {return false;}if(cur.left!=null) {queue[r++]=cur.left;}if(cur.right!=null) {queue[r++]=cur.right;}if(cur.left==null||cur.right==null) {leaf=true;}}return true;
}
三. 完全二叉树的节点个数(时间复杂度低于O(n))
//给定节点,计算该节点到最底层的高度,设初始高度为1public static int mostLeft(TreeNode cur,int level) {while(cur!=null) {level++;cur=cur.left;}return level-1;}//cur: 当前节点//h: 整颗完全二叉树的高度,不是当前节点到底部的高度//level: 当前节点所在的高度//dfs2: 计算当前节点cur的节点个数public static int dfs2(TreeNode cur,int level,int h) {if(level==h) return 1; //如果cur在最后一层,即叶子节点,显然节点数为1if(mostLeft(cur.right, level+1)==h) { return (1<<(h-level))+dfs2(cur.right,level+1,h); //再以右孩子为根,因此level+1}else {return (1<<(h-level-1))+dfs2(cur.left,level+1,h);//再以右孩子为根,因此level+1}}public int countNodes2(TreeNode root) {if(root==null) {return 0;}return dfs2(root,1,mostLeft(root, 1));}
参考于:视频链接