例题集 树

  1. 实现二叉树的先序、中序、后序遍历(递归方式)
  2. 实现二叉树的先序、中序、后序遍历(非递归方式)
  3. 直观的打印一颗二叉树
  4. 在二叉树中找到一个节点的后继节点(中序遍历的下一个结点为后继结点)
  5. 在二叉树中找到一个节点的前驱节点(中序遍历的前一个结点为前驱结点)
  6. 二叉树的序列化和反序列化(先序、层序)
  7. 判断一棵二叉树是否是平衡二叉树
  8. 判断一棵树是否是搜索二叉树(递归与非递归)
  9. 判断一棵树是否是完全二叉树
  10. 已知一棵完全二叉树,求其节点的个数
  11. 求最大深度
  12. 判断是否是对称二叉树
  13. 求最小深度
  14. 求二叉搜索树相邻结点绝对值的最小差值
  15. 求所有从根节点到叶子节点的路径
  16. 最近公共祖先
  17. 二叉搜索树的范围和
  18. 二叉树的层序遍历
  19. 二叉树的锯齿形层序遍历
  20. 翻转二叉树

1.实现二叉树的先序、中序、后序遍历(递归方式)
先序

    private static void preOrder(Node nodeHead) {
        if (nodeHead == null){
            return;
        }
        //在第一次访问该结点的时候打印
        System.out.println(nodeHead.value);
        preOrder(nodeHead.left);
        preOrder(nodeHead.right);
    }

中序

    private static void inOrder(Node nodeHead) {
        if (nodeHead == null){
            return;
        }
        inOrder(nodeHead.left);
        //在第二访问该结点的时候打印
        System.out.println(nodeHead.value);
        inOrder(nodeHead.right);
    }

后序

    private static void posOrder(Node nodeHead) {
        if (nodeHead == null){
            return;
        }
        posOrder(nodeHead.left);
        posOrder(nodeHead.right);
        System.out.println(nodeHead.value);
        //在第三次访问该结点的时候打印
    }

2.实现二叉树的先序、中序、后序遍历(非递归方式)
先序

思路:
(1)用栈实现
(2)先将头结点压入栈
(3)如果栈不为空,弹出栈顶并打印该结点;如果该结点有右孩子就先压右孩子;
如果该结点有左孩子就再压左孩子
(4)重复步骤(3)
    private static void preOrder(Node nodeHead) {
        if (nodeHead != null){
            Stack<Node> stack = new Stack<>();
            //先压入头结点
            stack.push(nodeHead);
            while (!stack.isEmpty()){
                //弹出栈顶
                nodeHead = stack.pop();
                System.out.println(nodeHead.value);
                //有右孩子先压右孩子
                if (nodeHead.right != null){
                    stack.push(nodeHead.right);
                }
                //有左孩子再压左孩子
                if (nodeHead.left != null){
                    stack.push(nodeHead.left);
                }
            }
        }
    }

中序

思路:
(1)用栈实现
(2)如果当前Node!=null,压入Node,指针指向Node左孩子
(3)如果当前Node==null,弹出栈顶打印,指针指向Node右孩子
    private static void inOrder(Node nodeHead) {
        if (nodeHead != null){
            Stack<Node> stack = new Stack<>();
            while (!stack.isEmpty() || nodeHead != null){
                //左孩子不为空就压自己 指针指向左孩子
                if (nodeHead != null){
                    stack.push(nodeHead);
                    nodeHead = nodeHead.left;
                }else {
                    //没左孩子 弹出栈顶 并压栈顶的右孩子
                    nodeHead = stack.pop();
                    System.out.println(nodeHead.value);
                    nodeHead = nodeHead.right;
                }
            }
        }
    }

后序

思路:
(1)用两个栈 栈1和栈2
(2)先将头结点压入栈1
(3)如果栈1不为空,弹出栈1顶放进栈2;
栈1顶如果有左孩子就往栈1压入左孩子;
栈1顶如果有右孩子再往栈1压入右孩子
(4)重复步骤(3)
(5)栈1为空时,挨个打印栈2
    private static void posOrder(Node head){

        if (head != null){

            Stack<Node> stack1 = new Stack<>();
            Stack<Node> stack2 = new Stack<>();
            //先压入头结点
            stack1.push(head);

            while (!stack1.isEmpty()){
                head = stack1.pop();
                //该打印时不打印 压入stack2
                stack2.push(head);
                //有左孩子压左孩子  ->  最终栈2里是逆序打印,所以跟先序打印反过来,先压左孩子再压右孩子
                if (head.left != null){
                    stack1.push(head.left);
                }
                //有右孩子再压右孩子
                if (head.right != null){
                    stack1.push(head.right);
                }
            }
            //最终挨个打印栈2
            while (!stack2.isEmpty()){
                System.out.println(stack2.pop().value);
            }
        }
    }

3.直观的打印一颗二叉树
不是面试/笔试题 -> 用于自己来判断二叉树的结构是否正确

public class printTree27 {
    public static void main(String[] args) {
        Node nodeHead = getNodeHead();
        printTree(nodeHead);

    }

    public static void printTree(Node head) {
        System.out.println("Binary Tree:");
        printInOrder(head, 0, "H", 17); //占用长度为17
        System.out.println();
    }

    public static void printInOrder(Node head, int height, String to, int len) {
        if (head == null) {
            return;
        }
        //先右子树、再根节点、最后左子树的遍历过程
        printInOrder(head.right, height + 1, "v", len);

        String val = to + head.value + to;
        int lenM = val.length();
        int lenL = (len - lenM) / 2;
        int lenR = len - lenM - lenL;
        val = getSpace(lenL) + val + getSpace(lenR);

        System.out.println(getSpace(height * len) + val);

        printInOrder(head.left, height + 1, "^", len);
    }

    public static String getSpace(int num) {
        String space = " ";
        StringBuffer buf = new StringBuffer("");
        for (int i = 0; i < num; i++) {
            buf.append(space);
        }
        return buf.toString();
    }


    private static Node getNodeHead() {
        Node head = new Node(0);
        Node node1 = new Node(1);
        head.left = node1;
        Node node2 = new Node(2);
        head.right = node2;
        Node node3 = new Node(3);
        node1.left = node3;
        Node node4 = new Node(4);
        node1.right = node4;
        Node node5 = new Node(5);
        node2.left = node5;

        return head;
    }

    public static class Node{
        public int value;
        public Node left;
        public Node right;
        public Node(int value){
            this.value = value;
        }
    }
}

4.在二叉树中找到一个节点的后继节点(中序遍历的下一个结点为后继结点)

思路:
(1)如果该结点node有右孩子,那么node的后继结点一定的其右子数的最左孩子
(2)如果该结点node没有右孩子,就找该结点的父结点parent	->
(3)如果该结点node的父结点parent的左孩子就是该结点node,那么node的后继结点就是parent
(4)如果该结点的结点parent的左孩子不是该结点node,则node,parent同时上移,重复步骤(3)
    private static Node inBinaryTreeGetNextNode(Node node){
        //记录父结点
        Node parent = null;
        //判空
        if (node == null){
            return null;
        }
        //如果有右孩子 就是右孩子为子树头结点的树中,最左孩子
        if (node.right != null){
            parent = getLeftMost(node.right);
        }else {
            //如果没有右孩子 找父结点
            parent = node.parent;
            while (parent != null) {
                //如果当前结点是父结点的左孩子 那么父结点就是后继结点
                if (parent.left == node){
                    break;
                }else {
                    //如果当前结点是父结点的右孩子 那么继续往上找
                    node = parent;
                    parent = node.parent;
                }
            }
        }
        return parent;
    }

    private static Node getLeftMost(Node node){
        if (node.left == null){
            return node;
        }

        while (node.left != null){
            node = node.left;
        }

        return node;
    }

    //时间 76.39
    //空间 51.08
    private boolean hasVisit;
    public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        hasVisit = false;
        return dfs(root, p);
    }

    public TreeNode dfs(TreeNode node, TreeNode p) {
        if (node == null) return null;

        // 遇到目标节点就将访问标记置为true
        if (node == p) hasVisit = true;
        TreeNode left = dfs(node.left, p);
        if (hasVisit && node.val > p.val) {
            // 第一次满足if时,当前节点就是答案
            // 之后的就不是直接后继了,所以将访问标记置为false
            hasVisit = false;
            return node;
        }
        TreeNode right = dfs(node.right, p);

        return left == null ? right : left;
    }

5.在二叉树中找到一个节点的前驱节点(中序遍历的前一个结点为前驱结点)

思路:
(1)如果该结点node有左孩子,那么node的前驱结点一定是其左子树的最右孩子
(2)如果该结点node没有右孩子,就找该结点的父结点parent	->
(3)如果该结点node的parent的右孩子就是node,那么那么parent就是node的前驱结点
(4)如果该结点node的parent的右孩子不是node,node,parent同时上移,重复步骤(3)
    private static Node inBinaryTreeGetNextNode(Node node){
        //记录父结点
        Node parent = null;
        //判空
        if (node == null){
            return null;
        }
        //如果有右孩子 就是右孩子为子树头结点的树中,最左孩子
        if (node.right != null){
            parent = getRightMost(node.right);
        }else {
            //如果没有右孩子 找父结点
            parent = node.parent;
            while (parent != null) {
                //如果当前结点是父结点的右孩子 那么父结点就是前驱结点
                if (parent.right == node){
                    break;
                }else {
                    //如果当前结点是父结点的右孩子 那么继续往上找
                    node = parent;
                    parent = node.parent;
                }
            }
        }
        return parent;
    }

    private static Node getLeftMost(Node node){
        if (node.left == null){
            return node;
        }

        while (node.left != null){
            node = node.left;
        }

        return node;
    }

6二叉树的序列化和反序列化
先序序列化

思路:
(1)递归
(2)如果当前结点为空,返回 #_
(3)如果当前结点不为null,返回 value+_ ,遍历左子树,再遍历右子数
    private static String serialBinaryTreeByPre(Node head){
        String returnString = "";
        //判空
        if (head == null){
            return "#_";
        }
        returnString = head.value + "_";
        returnString = returnString + serialBinaryTreeByPre(head.left);
        returnString = returnString + serialBinaryTreeByPre(head.right);

        return returnString;
    }

先序反序列化

思路:
(1)先将Sting按照_分解
(2)将分解得到的数据依次添加进队列
(3)队列进行递归
(4)弹出头结点,如果头结点为null,返回null
(5)头结点不为null,遍历左子树,再遍历右子树
    //先序反序列化
    private static Node reconByPre(String tree){
        //判空
        if (tree == null){
            return null;
        }

        Queue<String> queue = new LinkedList<>();

        //分解
        String[] split = tree.split("_");
        for (int i = 0;i < split.length;i++){
            queue.offer(split[i]);
        }

        return reconPreOrder(queue);
    }

    //先序反序列化
    public static Node reconPreOrder(Queue<String> queue) {
        String poll = queue.poll();
        if (poll.equals("#")){
            return null;
        }

        Node head = new Node(Integer.parseInt(poll));
        head.left = reconPreOrder(queue);
        head.right = reconPreOrder(queue);

        return head;
    }

层序序列化
思路

  1. 将头结点压入队列
  2. while循环判断-> 依次从队列弹出头结点->如果结点为null或者不为null,字符串标记
  3. 如果该结点左孩子不为空,压入左孩子,如果左孩子为空,压入null作为标记
  4. 如果该结点右孩子不为空,压入右孩子,如果右孩子为空,压入null作为标记
    //层序序列化
    private static String serialBinaryTreeByLevel(Node head){
        //判空
        if (head == null){
            return "#_";
        }

        String returnString ="";

        Queue<Node> queue = new LinkedList<>();
        //将头结点压入
        queue.offer(head);
        while (!queue.isEmpty()){
            head = queue.poll();
            if (head == null){
                returnString = returnString + "#_";
            }else {
                returnString = returnString + head.value + "_";
                //左孩子不为空则压入左孩子 否则压入一个null为标记
                if (head.left != null){
                    queue.offer(head.left);
                }else {
                    queue.offer(null);
                }
                //右孩子不为空则压入右孩子 否则压入一个null为标记
                if (head.right != null){
                    queue.offer(head.right);
                }else {
                    queue.offer(null);
                }
            }

        }
        return returnString;
    }

层序反序列化
思路:

(1)先将字符串结构
(2)用指针标记数组,将第一个结点压入队列
(3)while循环
(4)得到头结点左孩子,如果不为空则压入队列
(5)得到头结点右孩子,如果不为空则压入队列
   //层序反序列化
    private static Node reconByLevel(String tree){
        //判空
        if (tree == null || tree.equals("#_")){
            return null;
        }

        String[] split = tree.split("_");
        //记录下标
        int curNum = 0;
        //创建头结点
        Node head = generatedNode(split[curNum++]);
        //创建当前结点
        Node curNode = head;
        //创建队列
        Queue<Node> queue = new LinkedList<>();
        //压入头结点
        queue.offer(curNode);

        while (!queue.isEmpty()){
            curNode = queue.poll();
            curNode.left = generatedNode(split[curNum++]);
            curNode.right = generatedNode(split[curNum++]);

            if (curNode.left != null){
                queue.offer(curNode.left);
            }

            if (curNode.right != null){
                queue.offer(curNode.right);
            }
        }

        return head;
    }

    private static Node generatedNode(String string){
        if (string.equals("#")){
            return null;
        }

        return new Node(Integer.parseInt(string));
    }

7.判断一棵二叉树是否是平衡二叉树
思路:

(1)创建新类保存信息:树的高度和是否是平衡树
(2)递归
(3)递归左孩子,如果为不平衡树,返回false
(4)递归右孩子,如果为不平衡树,返回false
(5)判断左子树右子树的高度,如果为不平衡树,返回false
(6)返回左子树和右子树最大高度+1,true
    //定义返回类型类
    private static class returnClass{
        int height;
        boolean isBalance;

        public returnClass(int height, boolean isBalance) {
            this.height = height;
            this.isBalance = isBalance;
        }
    }

    private static returnClass isBalanceBinaryTree(Node head){
        //判空
        if (head == null){
            return new returnClass(0,true);
        }

        returnClass leftTree = isBalanceBinaryTree(head.left);
        if (!leftTree.isBalance){
            return new returnClass(0,false);
        }

        returnClass rightTree = isBalanceBinaryTree(head.right);
        if (!rightTree.isBalance){
            return new returnClass(0,false);
        }

        if (Math.abs(leftTree.height - rightTree.height) > 1){
            return new returnClass(0,false);
        }

        return new returnClass(Math.max(leftTree.height,rightTree.height)+1,true);
    }

8.判断一棵树是否是搜索二叉树
非递归
思路:

(1)中序遍历应该按中小到大排序
    private static boolean isBST(Node head){
        //判空
        if (head == null){
            return true;
        }
        Stack<Node> stack = new Stack<>();
        long value = Integer.MIN_VALUE;
        boolean isBST = true;

        while (!stack.isEmpty() || head != null){
            if (head != null){
                stack.push(head);
                head = head.left;
            }else {
                head = stack.pop();
                if (value < head.value){
                    value = head.value;
                }else {
                    isBST = false;
                    break;
                }
                head = head.right;
            }
        }

        return isBST;
    }

递归

    //递归
    static long pre = Long.MIN_VALUE;
    static boolean isBST = true;

    //递归
    public static void isValidBST(Node root) {
        //判空
        if (root == null){
            return;
        }

        isValidBST(root.left);

        if (pre < root.value){
            pre = root.value;
        }else {
            isBST = false;
        }

        isValidBST(root.right);
    }

9.判断一棵树是否是完全二叉树
思路:

(1)层序遍历
(2)如果没有左孩子,有右孩子一定不是完全二叉树
(3)如果遇到了有左孩子,没有右孩子的情况,之后再遇到一定不是完全二叉数
(3)遇到了有左孩子,没有右孩子的情况标记
    private static boolean isCST(Node head){
        //判空
        if (head == null){
            return true;
        }

        Queue<Node> queue = new LinkedList<>();
        queue.offer(head);
        //标记是否遇到过叶结点
        boolean havedLeft = false;


        while (!queue.isEmpty()){
            head = queue.poll();
            //如果有右孩子而没有左孩子那么一定不是搜索二叉树  或者  遇到了叶结点之后还遇到了非叶结点
            if ((head.left == null && head.right != null) || (havedLeft && head.left != null)){
                return false;
            }
            //左孩子不为空 压入队列
            if (head.left != null){
                queue.offer(head.left);
            }
            //右孩子不为空 压入队列
            if (head.right != null){
                queue.offer(head.right);
            }
            //如果左孩子为空 右孩子不为空 那么遇到了叶结点 只可能遇见一次叶结点
            if (head.left != null && head.right == null){
                havedLeft = true;
            }
        }


        return true;
    }

10.已知一棵完全二叉树,求其节点的个数
思路:

(1)递归
(2)如果该结点右子树最左结点碰到最底,那么左子树为满二叉树,右子树继续递归
(3)如果该结点右子树最左结点没有碰到最底,那么右子树为满二叉树,左子树继续递归
    private static int isCSTAndNodeNum(Node head){
        //判空
        if (head == null){
            return 0;
        }

        return getNodeNum(head, 1, mostLeftLevel(head,1));
    }

    private static int getNodeNum(Node head,int level,int height){

        if (height == level){
            return 1;
        }

        //如果该结点的右子树最左结点碰到该树深度   ->  那么该结点左子树为满二叉树   ->  右子树继续递归
        if (mostLeftLevel(head.right,level + 1) == height){
            return (1<< (height-level)) + getNodeNum(head.right,level + 1,height);
        }else {
        //如果该结点的右子树最左结点没有碰到该树深度   ->  那么该结点右子树为满二叉树 (高度-1)  ->  左子树继续递归
            return (1<< (height - level - 1)) + getNodeNum(head.left,level + 1,height);
        }
    }


    private static int mostLeftLevel(Node node,int level){
        while (node != null){
            node = node.left;
            level++;
        }
        return level - 1;
    }

11.求最大深度
题目:
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

//时间 100
//空间 42
//深度优先
    public int maxDepth_recursion(TreeNode root) {
        if (root == null){
            return 0;
        }

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

        return Math.max(left,right) + 1;
    }
//时间 17.79
//空间 29.04
    //广度优先
    public int maxDepth_NoRecursion(TreeNode root) {
        if (root == null){
            return 0;
        }

        //队列维护一层所有结点
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int res = 0;

        while (!queue.isEmpty()){
            int size = queue.size();
            while (size > 0){
                TreeNode poll = queue.poll();
                if (poll.left != null){
                    queue.offer(poll.left);
                }
                if (poll.right != null){
                    queue.offer(poll.right);
                }
                size--;
            }
            res++;
        }

        return res;
    }

12.判断是否是对称二叉树
题目:给定一个二叉树,检查它是否是镜像对称的。

//时间 27.49
//空间 5.09
    public boolean isSymmetric(TreeNode root) {
        if (root == null){
            return true;
        }

        return check_Norecursion(root.left,root.right);
    }
    
    public boolean check_Norecursion(TreeNode left, TreeNode right) {
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(left);
        queue.offer(right);

        while (!queue.isEmpty()){
            TreeNode poll1 = queue.poll();
            TreeNode poll2 = queue.poll();

            if (poll1 == null && poll2 == null){
                continue;
            }
            //只剩 都不为空 或者 只有一个为空 的情况
            if ((poll1 == null || poll2 == null) ||( poll1.val != poll2.val)){
                return false;
            }

            queue.offer(poll1.left);
            queue.offer(poll2.right);

            queue.offer(poll1.right);
            queue.offer(poll2.left);
        }

        return true;
    }
//时间 100
//空间 76
    public boolean isSymmetric(TreeNode root) {
        if (root == null){
            return true;
        }

        return check_Recursion(root.left,root.right);
    }
    
    public boolean check_Recursion(TreeNode left, TreeNode right) {
        if (left == null && right == null){
            return true;
        }
        //只剩 有一个为空 或者 都不为空 的情况
        if (left == null || right == null){
            return false;
        }

        return (left.val == right.val) &&
                check_Recursion(left.right,right.left) &&
                check_Recursion(left.left,right.right);
}

13.求最小深度
题目:
最小深度是从根节点到最近叶子节点的最短路径上的节点数量

    public int minDepth(TreeNode root) {
        if (root == null){
            return 0;
        }

        return count_Recursion(root);
    }

//时间 62
//空间 27
    //递归
    public int count_Recursion(TreeNode root){
        if (root == null){
            return Integer.MAX_VALUE;
        }

        if (root.left == null && root.right == null){
            return 1;
        }

        int left = count_Recursion(root.left);
        int right = count_Recursion(root.right);
        return Math.min(left,right) + 1;
    }
    public int minDepth(TreeNode root) {
        if (root == null){
            return 0;
        }

        return count_Guang(root);
    }

//时间 99.77
//空间 79.84
    //广度遍历
    public int count_Guang(TreeNode root){
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int res = 0;
        int size = 1;
        boolean isLeft = false;
        while (!queue.isEmpty()){
            size = queue.size();
            while (size > 0){
                TreeNode poll = queue.poll();
                if (poll.left == null && poll.right == null){
                    isLeft = true;
                    break;
                }
                if (poll.left != null){
                    queue.offer(poll.left);
                }
                if (poll.right != null){
                    queue.offer(poll.right);
                }
                size--;
            }

            res++;
            if (isLeft){
                break;
            }
        }

        return res;
    }

14.求二叉搜索树相邻结点绝对值的最小差值
题目:给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值

    static int res = Integer.MAX_VALUE;
    static int pre = 0;
    static boolean isFirst = true;
//时间 100
//空间 64.72
    public static int minDiffInBST_Recursion(TreeNode root){
        if (root == null){
            return 0;
        }

        count(root);

        return res;
    }

    public static void count(TreeNode root) {
        if (root == null){
            return;
        }

        count(root.left);

        if (isFirst){
            pre = root.val;
            isFirst = false;
        }else {
            res = Math.min(res, Math.abs(pre - root.val));
            pre = root.val;
        }

        count(root.right);
    }
//时间 100
//空间 11
    public static int minDiffInBST_NoRecursion(TreeNode root) {
        if (root == null){
            return 0;
        }

        Stack<TreeNode> stack = new Stack<>();
        int res = Integer.MAX_VALUE;
        int pre = 0;
        boolean isFirst = true;

        while (!stack.isEmpty() || root != null){

            if (root != null){
                stack.push(root);
                root = root.left;
            }else {
                root = stack.pop();

                if(isFirst){
                    pre = root.val;
                    isFirst = false;
                }else {
                    res = Math.min(res, Math.abs(pre - root.val));
                    pre = root.val;
                }

                root = root.right;
            }
        }
        return res;
    }

15.求所有从根节点到叶子节点的路径
题目:
给定一个二叉树,返回所有从根节点到叶子节点的路径

//时间 39.21
//空间 23.21
    public List<String> binaryTreePaths(TreeNode root) {

        List<String> list = new ArrayList<>();
        constructPaths(root,"",list);

        return list;
    }

    public void constructPaths(TreeNode root, String path, List<String> paths) {

        if (root == null){
            return;
        }

        constructPaths(root.left,path + root.val + "->",paths);
        constructPaths(root.right,path + root.val + "->",paths);

        if (root.left == null && root.right == null){
            paths.add(path + root.val);
        }

    }

16.最近公共祖先
题目:
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先

//时间 20.90
//空间 5.62
    //记录所有  【左\右子节点的值,当前结点】
    Map<Integer,TreeNode> parents = new HashMap<>();
    Set<Integer> visited = new HashSet<>();

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {

        write(root);

        while (p != null){
            visited.add(p.val);
            p = parents.get(p.val);
        }

        while (q != null){
            if (visited.contains(q.val)){
                return q;
            }
            q = parents.get(q.val);
        }

        return null;
    }

    public void write(TreeNode root){
        if (root.left != null){
            parents.put(root.left.val,root);
            write(root.left);
        }
        if (root.right != null){
            parents.put(root.right.val,root);
            write(root.right);
        }
    }
//时间 100
//空间 32.23
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {

        if (root == q || root == p){
            return root;
        }

        if (root != null){
            TreeNode treeNodeLeft = lowestCommonAncestor(root.left, p, q);
            TreeNode treeNodeRight = lowestCommonAncestor(root.right, p, q);
            if (treeNodeLeft != null && treeNodeRight != null){
                return root;
            }else if (treeNodeLeft == null){
                return treeNodeRight;
            }else {
                return treeNodeLeft;
            }
        }

        return null;
    }
//时间 100
//空间 77.52
    TreeNode res = null;

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        dfs(root, p, q);
        return res;
    }

    public boolean dfs(TreeNode root, TreeNode p, TreeNode q){
        if (root == null){
            return false;
        }


        boolean left = dfs(root.left, p, q);
        boolean right = dfs(root.right, p, q);

        if (((root.val == q.val || root.val == p.val) && (left || right)) || (left && right)){
            res = root;
        }

        return left || right || (root.val == q.val || root.val == p.val);
    }

17.二叉搜索树的范围和
题目:给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和。

//时间 53
//空间 73
    int res = 0;

    public int rangeSumBST_Recursion(TreeNode root, int low, int high) {
        if (root == null){
            return 0;
        }

        count(root,low,high);
        return res;
    }

    public void count(TreeNode root, int low, int high) {
        if (root == null){
            return;
        }

        count(root.left,low,high);

        if (low <= root.val && root.val <= high){
            res += root.val;;
        }
        
        count(root.right,low,high);

    }
//时间 7.26
//空间 68.97
    public int rangeSumBST_NoRecursion(TreeNode root, int low, int high) {
        int res = 0;
        Stack<TreeNode> stack = new Stack<>();

        while (!stack.isEmpty() || root != null){
            if(root != null){
                stack.push(root);
                root = root.left;
            }else {
                root = stack.pop();

                res = low <= root.val && root.val <= high ?  res + root.val : res;

                root = root.right;
            }
        }
     return res;
    }

18.二叉树的层序遍历
题目:
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。

//时间 93.89
//空间 25.04
    public static List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> listRes = new ArrayList<>();

        if (root == null){
            return listRes;
        }

        Queue<TreeNode> queue1 = new LinkedList<>();
        Queue<TreeNode> queue2 = new LinkedList<>();

        queue1.offer(root);

        while (!queue1.isEmpty()){
            levelCount(listRes,queue1,queue2);

            Queue<TreeNode> tmp = null;
            tmp = queue1;
            queue1 = queue2;
            queue2 = tmp;
        }

        return listRes;
    }

    public static void levelCount(List<List<Integer>> listRes,Queue<TreeNode> queue1,Queue<TreeNode> queue2){
        List<Integer> list = new ArrayList<>();

        while (!queue1.isEmpty()){
            TreeNode poll = queue1.poll();
            list.add(poll.val);
            System.out.println("poll.val = " + poll.val);

            if (poll.left != null){
                queue2.offer(poll.left);
            }
            if (poll.right != null){
                queue2.offer(poll.right);
            }
        }

        listRes.add(list);
    }
//时间 93.89
//空间 17.22
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> listRes = new ArrayList<>();

        if (root == null){
            return listRes;
        }

        Queue<TreeNode> queue1 = new LinkedList<>();
        queue1.offer(root);

        while (!queue1.isEmpty()){

            List<Integer> list = new ArrayList<>();

            int size = queue1.size();
            for (int i = 0; i < size; i++) {
                TreeNode poll = queue1.poll();
                list.add(poll.val);

                if (poll.left != null){
                    queue1.offer(poll.left);
                }
                if (poll.right != null){
                    queue1.offer(poll.right);
                }
            }
            listRes.add(list);

        }

        return listRes;
    }

19.二叉树的锯齿形层序遍历
题目:
给定一个二叉树,返回其节点值的锯齿形层序遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

//时间 97.37
//空间 30.28
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {

        List<List<Integer>> listRes = new ArrayList<>();
        if (root == null){
            return listRes;
        }

        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();

        stack1.push(root);
        boolean isSingle = true;

        while (!stack1.isEmpty()){
            int size = stack1.size();
            List<Integer> list = new ArrayList<>();
            //如果当前层数是单数 ->  先压左再压右
            if (isSingle){
                for (int i = 0; i < size; i++) {

                    root = stack1.pop();
                    list.add(root.val);

                    if (root.left != null){
                        stack2.push(root.left);
                    }
                    if (root.right != null){
                        stack2.push(root.right);
                    }
                }

                Stack<TreeNode> tmp = null;
                tmp = stack2;
                stack2 = stack1;
                stack1 = tmp;

                isSingle = false;
            }else {
                //如果当前层数是双数 ->  先压右再压左
                for (int i = 0; i < size; i++) {

                    root = stack1.pop();
                    list.add(root.val);

                    if (root.right != null){
                        stack2.push(root.right);
                    }

                    if (root.left != null){
                        stack2.push(root.left);
                    }
                }
                Stack<TreeNode> tmp = null;
                tmp = stack2;
                stack2 = stack1;
                stack1 = tmp;
                isSingle = true;
            }
            listRes.add(list);
        }
        return listRes;
    }
//时间 97.37
//空间 5.18
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> ans = new LinkedList<List<Integer>>();
        if (root == null) {
            return ans;
        }

        Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();
        nodeQueue.offer(root);
        boolean isOrderLeft = true;

        while (!nodeQueue.isEmpty()) {
            Deque<Integer> levelList = new LinkedList<Integer>();
            int size = nodeQueue.size();
            for (int i = 0; i < size; ++i) {
                TreeNode curNode = nodeQueue.poll();
                if (isOrderLeft) {
                    levelList.offerLast(curNode.val);
                } else {
                    levelList.offerFirst(curNode.val);
                }
                if (curNode.left != null) {
                    nodeQueue.offer(curNode.left);
                }
                if (curNode.right != null) {
                    nodeQueue.offer(curNode.right);
                }
            }
            ans.add(new LinkedList<Integer>(levelList));
            isOrderLeft = !isOrderLeft;
        }

        return ans;
    }

20.翻转二叉树

    //时间100
    //空间72.97
    public TreeNode invertTree(TreeNode root) {
        if (root == null){
            return null;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            TreeNode poll = queue.poll();
            TreeNode tmp = poll.left;
            poll.left = poll.right;
            poll.right = tmp;
            if (poll.left != null){
                queue.offer(poll.left);
            }
            if (poll.right != null){
                queue.offer(poll.right);
            }
        }

        return root;
    }
    //时间100
    //空间97.75
    public TreeNode invertTree_Re(TreeNode root) {
        if (root == null){
            return null;
        }

        TreeNode tmp = root.right;
        root.right = root.left;
        root.left = tmp;

        invertTree_Re(root.left);
        invertTree_Re(root.right);

        return root;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值