面试常见二叉树算法题集锦-Java实现
1.求二叉树的深度或者说最大深度 /* ***1.求二叉树的深度或者说最大深度 */ public static int maxDepth(TreeNode root){ if(root==null) return 0; int left=maxDepth(root.left); int right=maxDepth(root.right); return Math.max(left,right)+1; } 2.求二叉树的最小深度 /* ***2.求二叉树的最小深度 */ public static int MinDepth(TreeNode root){ if(root==null) return 0; if(root.left==null&&root.right==null) return 1; int left=MinDepth(root.left); int right=MinDepth(root.right); if(root.left==null||root.right==null) return Math.max(left,right)+1; return Math.min(left,right)+1; } 3.求二叉树中节点的个数 /* ***3.求二叉树中节点的个数 */ public static int nodeCount(TreeNode root){ if(root==null) return 0; int left=nodeCount(root.left); int right=nodeCount(root.right); return left+right+1; } 4.求二叉树中叶子节点的个数 /* ***4.求二叉树中叶子节点的个数 */ public static int leafNodeCount(TreeNode root){ if(root==null) return 0; if(root.left==null&&root.right==null) return 1; int left=leafNodeCount(root.left); int right=leafNodeCount(root.right); return left+right; } 5.求二叉树中第k层节点的个数 /* ***5.求二叉树中第k层节点的个数 */ public static int KlevelCount(TreeNode root,int k){ if(root==null||k<1) return 0; if(k==1) return 1; //K=1的那一层总是我们想找的那一层 int left=KlevelCount(root.left,k-1); int right=KlevelCount(root.right,k-1); return left+right; //或者可以用层次遍历的方法 } 6.判断二叉树是否为平衡二叉树 /* ***6.判断二叉树是否为平衡二叉树 平衡二叉树的左右子树高度差的不超过1 */ public static boolean isBalancedTree(TreeNode root){ if(root==null) return false; return isBalancedhelper(root)!=-1; } public static int isBalancedhelper(TreeNode root){ if(root==null) return 0; int left=isBalancedhelper(root.left); int right=isBalancedhelper(root.right); if(Math.abs(left-right)>1) return -1; //返回-1说明不平衡 return Math.max(left,right)+1; } 7.判断二叉树是否是二叉完全树 /* ***7.判断二叉树是否是二叉完全树 */ public static boolean isCompleteTree(TreeNode root){ if(root==null) return false; Queue<TreeNode> queue=new LinkedList<>(); queue.add(root); boolean res=true; boolean hasNoChild=false; while(!queue.isEmpty()){ TreeNode tmp=queue.remove(); if(hasNoChild){ //hasNoChild=true说明在tmp节点之前有无右孩子的节点,这时tmp只能为叶子节点 if(tmp.left!=null||tmp.right!=null) return false; } else{ if(tmp.left!=null&&tmp.right!=null){ queue.add(tmp.left); queue.add(tmp.right); } else if(tmp.left!=null&&tmp.right==null){ queue.add(tmp.left); hasNoChild=true; } else if(tmp.left==null&&tmp.right!=null) return false; else hasNoChild=true; } } return res; } 8.两个二叉树是否完全相同 /* ***8.两个二叉树是否完全相同 */ public static boolean isSameTree(TreeNode root1,TreeNode root2){ if(root1==null) return root2==null; if(root2==null) return false; if(root1.val!=root2.val) return false; return isSameTree(root1.left,root2.left)&&isSameTree(root1.right,root2.right); } 9.两个二叉树是否为镜像二叉树 /* ***9.两个二叉树是否为镜像二叉树 */ private static boolean isMirror(TreeNode root1,TreeNode root2){ if(root1==null) return root2==null; //如果是判断某棵树是不是镜像的,令root2=root1即可 if(root2==null) return false; if(root1.val!=root2.val) return false; return isMirror(root1.left,root2.right)&&isMirror(root1.right,root2.left); } 10.翻转二叉树或者镜像二叉树 /* ***10.翻转二叉树或者镜像二叉树 */ private static boolean mirrorTree(TreeNode root){ if(root==null) return root; TreeNode left=mirrorTree(root.left); //先把左右子树都先翻转 TreeNode right=mirrorTree(root.right); root.left=right; //再把左右孩子节点反转 root.right=left; return root; } 11.求两个二叉树节点的最低公共祖先节点 /* ***11.求两个二叉树节点的最低公共祖先节点 */ private static TreeNode lastCommonParent(TreeNode root,TreeNode node1,TreeNode node2){ if(!lastCommonParentHelper(root,node1)||!lastCommonParentHelper(root,node2)) return null; if(lastCommonParentHelper(root.left,node1)){ //node1在左子树上 // if(lastCommonParentHelper(root.left,node2)) return lastCommonParent(root.left,node1,node2); //去root的左子树上看看 else { return root;//否则,1.如果两个节点分居root的两个子树,那么root就是最近父节点 2.node2是根节点或者右边的节点,那么公共节点一定是root } } else if(lastCommonParentHelper(root.right,node1)){ //node1不在左子树上,而在右子树上 //如果node2也在右子树上,那么就去右子树看看 if(lastCommonParentHelper(root.right,node2)) return lastCommonParent(root.right,node1,node2); else{ return root; //node2不在右子树,那么可能在root或者左子树,则root是最近根节点 } } else return root; } private static boolean lastCommonParentHelper(TreeNode root,TreeNode node){ //判断node是不是root的子结构 if(root==null||node=null) return false; //约定null不是任何树的子树 if(root==node) return true; return lastCommonParentHelper(root.left,node)||lastCommonParentHelper(root.right,node); } 12.二叉树的前序遍历 /* ***12.二叉树的前序遍历 用ArrayList<Integer>存储 */ private static ArrayList<Integer> preOrder(TreeNode root){ ArrayList<Integer> list=new ArrayList<>(); preOrder1(root,list); //preOrder2(root,list) return list; } //先序遍历的递归写法 private static void preOrder1(TreeNode root,ArrayList<Integer> list){ if(root==null) return ; list.add(root.val); preOrder1(root.left,list); preOrder1(root.right,list); } //先序遍历的迭代写法 private static void preOrder2(TreeNode root,ArrayList<Integer> list){ if(root==null) return ; Stack<Integer> stack=new Stack<>(); stack.push(root); while(!stack.isEmpty()){ TreeNode tmp=stack.pop(); list.add(tmp.val); if(tmp.right!=null) stack.push(tmp.right); //先把右节点入栈,这样出栈的时候总是左节点先读取 if(tmp.left!=null) stack.push(tmp.left); } return ; } 13.二叉树的中序遍历 /* ***13.二叉树的中序遍历 用ArrayList<Integer>存储 */ private static ArrayList<Integer> inOrder(TreeNode root){ ArrayList<Integer> list=new ArrayList<>(); inOrder1(root,list); //inOrder2(root,list) return list; } //中序遍历的递归写法 private static void inOrder1(TreeNode root,ArrayList<Integer> list){ if(root==null) return ; inOrder1(root.left,list); list.add(root.val); inOrder1(root.right,list); } //中序遍历的迭代写法 private static void inOrder(TreeNode root,ArrayList<Integer> list){ if(root==null) return ; Stack<Integer> stack=new Stack<>(); TreeNode p=root; while(p!=null||!stack.isEmpty()){ while(p!=null){ stack.push(p); p=p.left; } p=stack.pop(); list.add(p.val); p=p.right; } return ; } 14.二叉树的后序遍历 /* ***14.二叉树的后序遍历 用ArrayList<Integer>存储 */ private static ArrayList<Integer> postOrder(TreeNode root){ ArrayList<Integer> list=new ArrayList<>(); postOrder1(root,list); //postOrder2(root,list) return list; } //先序遍历的递归写法 private static void postOrder1(TreeNode root,ArrayList<Integer> list){ if(root==null) return ; postOrder1(root.left,list); postOrder1(root.right,list); list.add(root.val); } //后序遍历的迭代写法 private static void postOrder2(TreeNode root,ArrayList<Integer> list){ if(root==null) return ; Stack<Integer> stack=new Stack<>(); stack.push(root); while(!stack.isEmpty()){ TreeNode tmp=stack.pop(); list.add(tmp.val); if(tmp.left!=null) stack.push(tmp.left); //先把左节点入栈,这样出栈的时候总是右节点先读取 if(tmp.right!=null) stack.push(tmp.right); //进组的顺序为 根->右->左 正好和后续遍历的顺序相反 } Collections.reverse(list); //反转list即可 return ; } 15.二叉树的层次遍历 /* ***15.二叉树的层次遍历 */ private static ArrayList<ArrayList<Integer>> leverOrder(TreeNode root){ ArrayList<ArrayList<Integer>> listAll=new ArrayList<>(); if(root==null) return listAll; ArrayList<Integer> list=new ArrayList<Integer>(); Queue<TreeNode> queue=new LinkedList<>(); queue.add(root); int count=0,nextCount=1; while(!queue.isEmpty()){ TreeNode tmp=queue.remove(); list.add(tmp.val); count++; if(tmp.left!=null) queue.add(tmp.left); if(tmp.right!=null) queue.add(tmp.right); if(count==nextCount){ count=0; nextCount=queue.size(); listAll.add(new ArrayList<Integer>(list)); list.clear(); } } return listAll; } 16.先序遍历和中序遍历构造二叉树 /* ***16.先序遍历和中序遍历构造二叉树 */ private static TreeNode pre_in_BuildTree(int[] preorder,int[] inorder){ if(preorder.length!=inorder.length) return null; return pre_in_BuildTreeHelper(preorder,0,preorder.length-1,inorder,0,inorder.length-1); } private static TreeNode pre_in_BuildTreeHelper(int[] preorder,int preStart,int preEnd,int[] inorder,int inStart,int inEnd){ if(preStart>preEnd) return null; TreeNode root=new TreeNode(preorder[preStart]); int index=inStart; while(inorder[index]!=root.val) index++; root.left=pre_in_BuildTreeHelper(preorder,preStart+1,preStart+index-inStart,inorder,inStart,index-1); root.right=pre_in_BuildTreeHelper(preorder,preStart+index-inStart+1,preEnd,inorder,index+1,inEnd); return root; } 17.中序遍历和后续遍历构造二叉树 /* ***17.中序遍历和后续遍历构造二叉树 */ private static TreeNode in_post_BuildTree(int[] inorder,int[] postorder){ if(postorder.length!=inorder.length) return null; return in_post_BuildTreeHelper(inorder,0,inorder.length-1,postorder,0,postorder.length-1); } private static TreeNode in_post_BuildTreeHelper(int[] inorder,int inStart,int inEnd,int[] postorder,int postStart,int postEnd,){ if(postStart>postEnd) return null; TreeNode root=new TreeNode(postorder[postEnd]); int index=inStart; while(inorder[index]!=root.val) index++; root.left=in_post_BuildTreeHelper(inorder,inStart,index-1,postorder,postStart,postStart+index-inStart-1); root.right=in_post_BuildTreeHelper(inorder,index+1,inEnd,postorder,postStart+index-inStart,postEnd-1); return root; } 18.输入一个二叉树和一个整数,打印出从二叉树根节点到叶子节点的路径上所有节点值之和值等于输入整数所有的路径 /* ***18.输入一个二叉树和一个整数,打印出从二叉树根节点到叶子节点的路径上所有节点值之和值等于输入整数所有的路径 */ private static ArrayList<ArrayList<Integer>> findPath(TreeNode root, int target){ ArrayList<ArrayList<Integer>> listAll=new ArrayList<>(); if(root==null) return listAll; ArrayList<Integer> list=new ArrayList<>(); findPathHelper(root,target,listAll,list); return listAll; } private static void findPathHelper(TreeNode root, int target,ArrayList<ArrayList<Integer>> listAll,ArrayList<Integer> list){ if(root==null) return ; list.add(root.val); if(root.left==null&&root.right==null&&target==root.val) listAll.add(new ArrayList<Integer>(list)); findPathHelper(root.left,target-root.val,listAll,list); findPathHelper(root.right,target-root.val,listAll,list); list.remove(list.size()-1); } 19.二叉搜索树的第k小的节点(中序遍历解决) /* ***19.二叉搜索树的第k小的节点(中序遍历解决) */ private static TreeNode KthNode(TreeNode pRoot, int k) { if(pRoot==null||k==0) return null; Stack<TreeNode> stack=new Stack<>(); int count=0; TreeNode p=pRoot; while(p!=null||!stack.isEmpty()){ while(p!=null){ stack.push(p); p=p.left; } p=stack.pop(); if(++count==k) return p; p=p.right; } return null; } 20.输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。 /* ***20.输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。 */ private static boolean VerifySquenceOfBST(int [] sequence) { if(sequence.length==0) return false; if(sequence.length==1) return true; return isBST(sequence,0,sequence.length-1); } private static boolean isBST(int[] num,int start,int end){ if(start>=end) return true; int i=start; while(num[i]<num[end]) i++; for(int j=i;j<end;j++){ if(num[j]<num[end]) return false; } return isBST(num,start,i-1)&&isBST(num,i,end-1); } 21.给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。 /* ***21.给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。 ***注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。 */ public class TreeLinkNode { int val; TreeLinkNode left = null; TreeLinkNode right = null; TreeLinkNode next = null; //指向其父节点 TreeLinkNode(int val) { this.val = val; } } private static TreeLinkNode GetNext(TreeLinkNode pNode) { if(pNode==null) return null; if(pNode.right!=null){ pNode=pNode.right; while(pNode.left!=null){ pNode=pNode.left; } return pNode; } while(pNode.next!=null){ if(pNode.next.left==pNode) return pNode.next; pNode=pNode.next; } return null; } 22.判断二叉树是不是二叉搜索树 /* ***22.判断二叉树是不是二叉搜索树 */ private static boolean isBST(TreeNode root){ if(root==null) return false; //约定空树不是二叉搜索树 return isBSThelper(root,Long.MIN_VALUE,Long.MAX_VALUE); } private static boolean isBSThelper(TreeNode root,long low,long high){ if(root==null) return true; if(root.val<low||root.val>high) return false;//这里加不加等号取决于具体的二叉搜索树定义,如果不允许相等的值存在则加上等号 return isBSThelper(root.left,low,root.val)&&isBSThelper(root.right,root.val,high); } 23.求二叉树中节点的最大距离 /* ***23.求二叉树中节点的最大距离 */ private static int maxDistance=Integer.MIN_VALUE; private static int getMaxDistance(TreeNode root){ if(root==null) return 0; getMaxDistanceHelper(root); return maxDistance; } private static int getMaxDistanceHelper(TreeNode root){ if(root==null) return -1; int leftMaxDistance=getMaxDistanceHelper(root.left); int rightMaxDistance=getMaxDistanceHelper(root.right); int temptMaxDistance=leftMaxDistance+rightMaxDistance+2; if(temptMaxDistance>maxDistance) maxDistance=temptMaxDistance; return leftMaxDistance>rightMaxDistance?leftMaxDistance+1:rightMaxDistance+1; } 24.合并两棵二叉树 /* ***24.合并两棵二叉树 */ private static TreeNode mergeTrees(TreeNode t1, TreeNode t2) { if(t2==null) return t1; if(t1==null) return t2; TreeNode root=new TreeNode(t1.val+t2.val); root.left=mergeTrees(t1.left,t2.left); root.right=mergeTrees(t1.right,t2.right); return root; }