Bootstrap

【Java数据结构】二叉树相关算法

第一题:获取二叉树中结点个数

        得到二叉树结点个数,如果结点为空则返回0,然后再用递归计算左树结点个数+根结点(1个)+右树结点个数。 

public int nodeSize(Node root){
        if (root == null)
            return 0;
        return nodeSize1(root.left)+nodeSize1(root.right)+1;
}

第二题:获取叶子结点的个数

        得到叶子结点个数和结点总数的做法相同,也是判断是否为空,如果该结点的左子树和右子树的都为空时那么该结点就是叶子结点,总的叶子结点就是左边叶子结点+右边叶子结点。

public int leafSize(Node root){
    if (root == null)
        return 0;
    if (root.left == null && root.right == null)
        return 1;
    return leafSize(root.left)+leafSize(root.right);
}

第三题:获取第k层结点的个数

        道理和前面两题是一样,第一层有1个结点,第k层结点个数就是第k-1层的左子树+第k-1层右子树。

public int getNode(Node root, int k){
    if (root == null){
        return 0;
    }
    if (k == 1){
        return 1;
    }
    return getNode(root.left, k-1)+getNode(root.right, k-1);
}

第四题:获取二叉树高度

        求高度需要左子树高度和右子树高度中最大的那个就是二叉树的高度,加上根结点。

public int getHeight(Node root){
    if (root == null){
        return 0;
    }
    int left = getHeight(root.left);
    int right = getHeight(root.right);

    return Math.max(left,right)+1;
}

第五题:二叉树中是否存在val

         判断二叉树是否存在val,需要以下几步:

  • 判断是否为空
  • 该结点是否与val相同
  • 判断左子树中是否存在与val相同的结点
  • 判断右子树中是否存在与val相同的结点
  • 左右子树都不存在与val相同的结点,那就返回false
public boolean find(Node root, char val){
    if (root == null){
        return false;
    }
    if (root.val == val){
        return true;
    }
    boolean left = find(root.left, val);
    if (left == true){
        return true;
    }
    boolean right = find(root.right, val);
    if (right == true){
        return true;
    }
    return false;
}

第六题:判断两棵树是否相同

100. 相同的树 - 力扣(LeetCode)

        判断两棵树是否相同需要判断四种情况

  1. 两棵树都为空时
  2. 一棵为空,另一棵不为空时
  3. 两颗不为空,但是值不相同
  4. 两棵都不为空,值又相同时,再判断左子树和右子树是否同时符合
public boolean isSameTree(Node p, Node q) {
    if (q == null && p == null){
        return true;
    }
    if (q != null && p == null || q == null && p != null){
        return false;
    }
    if (q.val != p.val){
        return false;
    }
    return isSameTree(p.left, q.left)&& isSameTree(p.right, q.right);
}

第七题:判断是否是子树

572. 另一棵树的子树 - 力扣(LeetCode) 

         判断大的二叉树中是否存在一个小的二叉树,判断条件:

  • 如果大的二叉树的结点为空,小的二叉树不为空,则不是子树
  • 然后再判断两棵树是否相同,相同也是子树
  • 然后再遍历左子树的每一个结点,如果左子树存在子树返回true即可
  • 判断右子树的每个结点,存在子树则返回true
  • 左右都不存在子树返回false 
public boolean isSubtree(Node root, Node subRoot) {
    if (root == null){
        return false;
    }
    if (isSameTree(root, subRoot)) {
        return true;
    }
    boolean left = isSubtree(root.left, subRoot);
    if (left == true){
        return true;
    }
    boolean right = isSubtree(root.right, subRoot);
    if (right == true){
        return true;
    }
    return false;
}

第八题:反转二叉树

226. 翻转二叉树 - 力扣(LeetCode) 

        反转二叉树,主要就是反转每一个结点的左右子树,如果为空就结束,在这过程中使用了递归,最后返回根结点。

public Node invertTree(Node root) {
    if(root == null){
        return null;
    }
    Node temp = root.left;
    root.left = root.right;
    root.right = temp;

    invertTree(root.left);
    invertTree(root.right);
    return root;
}

第九题:判断是否是平衡二叉树

110. 平衡二叉树 - 力扣(LeetCode) 

        判断是否为平衡二叉树的主要条件是每棵子树的左右子树差值小于等于1;所以一边遍历一边比较差值。但是这个方法还有一个限制就是复杂度高(重复计算),可以直接在求高度是边计算差值。

public boolean isBalanced(Node root) {
        if(root == null){
            return false;
        }
        int left = getHeight(root.left);
        int right = getHeight(root.right);
        if (Math.abs(left - right) > 1){
            return false;
        }
        boolean leftB = isBalanced(root.left);
        boolean rightB = isBalanced(root.right);
        return true;
}

第十题:判断是否是对称二叉树

101. 对称二叉树 - 力扣(LeetCode) 

        判断是否对称的依据是根结点左右子树的结点是否对称,如果结构满足对称还需要结点对应的值相同(左子树的左结点需要与右子树的右结点相同)。

public boolean isSymmetric(Node root) {
    if (root == null){
        return true;
    }
    return isSymmetricChild(root.left, root.right);
}
public boolean isSymmetricChild(Node p, Node q) {
    if (p == null && q == null){
        return true;
    }
    if (p == null || q == null){
        return false;
    }
    if (p.val != q.val){
        return false;
    }
    return isSymmetricChild(p.left,q.right) && isSymmetricChild(p.right, q.left);
}

第十一题:分层遍历

102. 二叉树的层序遍历 - 力扣(LeetCode) 

        题目所表达的意思是将每一层的元素都进行输出;思路是从根结点开始先进行入队,先输出队列中的队头结点,然后每出一个元素就要将这个元素的左右结点都入队,直至队列为空。

如果需要返回一个链表,那就一次进一层(通过计算器计入队列中一层有多少元素,然后通过循环串联链表,并将串联在链表中的结点的左右结点都入队),直至队中节点为空。

public void levelOrder1(Node root){
    if (root == null){
        return ;
    }
    Queue<Node> q = new LinkedList<>();
    q.offer(root);
    while (!q.isEmpty()){
        Node cur = q.poll();
        System.out.print(cur.val+"  ");
        if (cur.left != null){
            q.offer(cur.left);
        }
        if (cur.right != null){
            q.offer(cur.right);
        }
    }
}

第十二题:最近公共祖先

236. 二叉树的最近公共祖先 - 力扣(LeetCode) 

        最近公共祖先意思就是在一棵树中挑两个结点然后向根结点的方向寻找两个结点最近的交点。所以要找出两个结点所有的情况,经实验总结了三种情况:两个结点同在左边、同在右边、以及一个结点在左边一个结点在右边。思路就是先判空再是如果有一个结点满足是根结点,那就直接返回根节点即可(在一个棵树中没有比根结点更大的祖先了),然后就开始遍历,在左右两边分别遍历,寻找两个结点的位置,然后就是返回最近祖先。

public Node lowestCommonAncestor(Node root, Node p, Node q){
    if (root == null){
        return null;
    }
    if (p == root || q == root){
        return root;
    }
    Node left = lowestCommonAncestor(root.left, p, q);
    Node right = lowestCommonAncestor(root.right, p, q);
    if (left != null && right != null){     //q和p一个在左一个在右
        return root;
    }else if (left != null){    //p和q都在左
        return left;
    }else{  //p和q都在右
        return right;
    }
}

;