二叉树问题合集

一.前言

二叉树是一种常见的基础数据结构,也是面试笔试中常常碰到的题目.

二叉树(英语:Binary tree)是每个节点最多只有两个分支(不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”和“右子树”。二叉树的分支具有左右次序,不能颠倒。

二叉查找树,可实现对元素的快速查找,对二叉树的理解也是学习其他树结构的基础.

二. 二叉树结构

class BinaryTree{
    int value;
    BinaryTree left;
    BinaryTree right;

    public BinaryTree(int value){
        this.value = value;
        this.left = null;
        this.right = null;
    }
}

三.常见链表问题

1. 树节点个数
2. 树的深度
3. 第K 层节点个数
4. 数的遍历:先序,中序,后序,层序
5. 树的镜像
6. 判断树中是否存在某元素
7. 是否是完全二叉树
8. 二叉树叶子节点个数
9. 判断两颗二叉树结构是否相同
10. 判断是否是平衡二叉树
11. 求二叉树中两个节点的最低公共祖先节点
12. 求二叉树中节点的最大距离
13. 由前序和中序遍历序列重建二叉树

四.题目

1. 树节点个数

1.1 思路

递归

1.2 代码

int getNumOfTree(BinaryTree root) {
    if (root == null) {
        return 0;
    }

    return 1+getNumOfTree(root.left)+getNumOfTree(root.right);
}

2. 树的深度

1.1 思路

递归

1.2 代码

int getDephthOfTree(BinaryTree root) {
    if (root == null) {
        return 0;
    }
    int leftHeight = getDephthOfTree(root.left);
    int rightHeight = getDephthOfTree(root.right);
    return leftHeight>rightHeight?leftHeight+1:rightHeight+1;
}

3. 第K 层节点个数

1.1 思路

递归

1.2 代码

private static int getNumberOfKth(BinaryTree root,int k) {
    if (root == null || k<1) {
        return 0;
    }

    if (k == 1) {
        return 1;
    }

    int kthLeft = getNumberOfKth(root.left, k-1);
    int kthRight = getNumberOfKth(root.right, k-1);

    return kthLeft+kthRight;
}

4. 数的遍历:先序,中序,后序,层序

1.1 思路

前序,中序,后序采用递归的方法,层序遍历借用队列来完成遍历.

1.2 代码

//前序
private static void preOrder(BinaryTree root) {
    if (root != null) {
        System.out.print(root.value+" ");
        preOrder(root.left);
        preOrder(root.right);
    }

}

//中序
private static void inOrder(BinaryTree root) {
    if (root != null) {
        inOrder(root.left);
        System.out.print(root.value+" ");
        inOrder(root.right);
    }
}

//后序
private static void postOrder(BinaryTree root) {
    if (root != null) {
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.value+" ");
    }
}

//层序
private static void leverOrder(BinaryTree root) {
    if (root == null) {
        return;
    }
    Queue queue = new LinkedList<>();
    queue.add(root);
    while(!queue.isEmpty()){
        BinaryTree pNode = queue.peek();
        System.out.print(pNode.value+" ");
        queue.remove();
        if (pNode.left != null) {
            queue.add(pNode.left);
        }
        if (pNode.right != null) {
            queue.add(pNode.right);
        }
    }

}

5. 树的镜像

1.1 思路

递归.

1.2 代码

private static BinaryTree mirror(BinaryTree root) {
    if (root == null) {
        return null;
    }
    BinaryTree left = mirror(root.left);
    BinaryTree right = mirror(root.right);

    root.left = right;
    root.right = left;

    return root;
}

6. 判断树中是否存在某元素

1.1 思路

任选一遍历方法进行查找.

1.2 代码

private static void Find(BinaryTree root,int number) {
    if (root != null) {
        if (root.value == number) {
            System.out.println("Found.");
            return;
        }
        Find(root.left, number);
        Find(root.right, number);
    }
}

7. 是否是完全二叉树

1.1 思路

使用队列进行遍历,若本层有未满子树,则下一层不应有节点.

1.2 代码

private static boolean isComplete(BinaryTree root) {
    if (root == null) {
        return true;
    }
    boolean hasNoChild = false;  //本层有未满子树,则下一次不应该有节点.
    boolean result = true;
    Queue queue = new LinkedList<>();
    queue.add(root);
    while(!queue.isEmpty()){
        BinaryTree pNode = queue.remove();
        if (hasNoChild) {
            if (pNode.left != null || pNode.right != null) { 
                result = false;
                break;
            }
        }else {
            if (pNode.left!= null && pNode.right != null) {
                queue.add(pNode.left);
                queue.add(pNode.right);
            }else if (pNode.left == null && pNode.right != null) {
                result = false;
                break;
            }else if(pNode.left != null && pNode.right == null){
                hasNoChild = true;  //进行下一轮扫描时,右子树为空
                queue.add(pNode.left);
            }else {
                hasNoChild = true;
            }
        }
    }
    return result;
}

8. 二叉树叶子节点个数

1.1 思路

递归.

1.2 代码

private static int getNumOfLeaf(BinaryTree root) {
    if (root == null) {
        return 0;
    }
    if (root.left == null && root.right == null) {
        return 1;
    }

    int left = getNumOfLeaf(root.left);
    int right = getNumOfLeaf(root.right);

    return left+right;
}

9. 判断两棵二叉树结构是否相同

1.1 思路

递归.

1.2 代码

private static boolean isCommon(BinaryTree root1, BinaryTree root2) {
    if (root1 == null && root2 == null) {
        return true;
    }else if (root1 == null || root2 == null) {
        return false;
    }

    boolean left = isCommon(root1.left, root2.left);
    boolean right = isCommon(root1.right, root2.right);

    return (left&&right);
}

10. 判断是否是平衡二叉树

1.1 思路

递归.

1.2 代码

private static boolean isAVL(BinaryTree root) {
    if (root == null) {
        return true;
    }
    int left_height = getDephthOfTree(root.left);
    int right_height = getDephthOfTree(root.right);

    int diff = left_height - right_height;

    if (diff <-1 || diff > 1) {
        return false;
    }
    return isAVL(root.left) && isAVL(root.right);
}

11. 求二叉树中两个节点的最低公共祖先节点

1.1 思路

从root开始遍历,如果n1和n2中的任一个和root匹配,那么root就是LCA。 如果都不匹配,则分别递归左、右子树,如果有一个 key(n1或n2)出现在左子树,并且另一个key(n1或n2)出现在右子树,则root就是LCA. 如果两个key都出现在左子树,则说明LCA在左子树中,否则在右子树。

1.2 代码

private static BinaryTree findLCA(BinaryTree root, BinaryTree pNode1, BinaryTree pNode2) {
    if (root == null) {
        return null;
    }
    if (root.value == pNode1.value || root.value == pNode2.value) {
        return root;
    }
    BinaryTree left_lca = findLCA(root.left, pNode1, pNode2);
    BinaryTree right_lca = findLCA(root.right, pNode1, pNode2);

    if (left_lca != null && right_lca != null) {
        return root;
    }

    return (left_lca !=null)?left_lca:right_lca;
}

12. 求二叉树中节点的最大距离

1.1 思路

递归.

1.2 代码

//最大距离Max(左子树最大距离,右子树最大距离,左子树节点到根节点的最大距离+右子树节点到根节点的最大距离)
private static int height(BinaryTree root) {
    if (root == null) {
        return 0;
    }

    int heightLeft = height(root.left);
    int heightRight = height(root.right);

    return heightLeft>heightRight?(heightLeft+1):(heightRight+1);
}

private static int getMaxDistance(BinaryTree root) {
    if (root == null) {
        return 0;
    }else if (root.left == null && root.right == null) {
        return 0;
    }

    int dis = max(height(root.left)+height(root.right),getMaxDistance(root.left),getMaxDistance(root.right));
    if (maxDis return dis;

}

private static int max(int a, int b, int c) {
    int temp = a>b?a:b;
    return temp>c?temp:c;
}

13. 由前序和中序遍历序列重建二叉树

1.1 思路

递归.

1.2 代码

private static BinaryTree buildTree(int[] preOrder, int startPre, int endPre, int[] inOrder, int startIn, int endIn) {
    if ((endPre-startPre) != (endIn-startIn)) {
        return null;
    }
    if (preOrder == null || inOrder == null || preOrder.length<1 || inOrder.length <1) {
        return null;
    }

    int rootValue = preOrder[startPre];
    BinaryTree root = new BinaryTree(rootValue);

    if ((startPre == endPre) && (startIn == endIn)) {
        return root;
    }

    int rootIdx = startIn;
    while (rootIdx <=endIn && inOrder[rootIdx]!=rootValue){
        rootIdx ++;
    }

    if (rootIdx>endIn) {
        return null;
    }
    int leftLength = rootIdx-startIn;
    int leftPreorderLeft = leftLength + startPre;
    if (leftLength>0) {
        root.left = buildTree(preOrder, startPre+1, leftPreorderLeft, inOrder, startIn, rootIdx-1);
    }
    if (leftLength1, endPre, inOrder, rootIdx+1, endIn);
    }

    return root;
}

参考文献

  1. 轻松搞定面试中的二叉树题目
  2. <剑指offer>
  3. 寻找二叉树两个节点的最低公共祖先

你可能感兴趣的:(Java,编程之美,剑指offer-java)