算法 - 二叉树

public class Tree {

    private Node root;

    public Tree() {
        root = null;
    }

    public Node getRoot() {
        return root;
    }

    //把LeetCode题目用例的数组生成树
    public Node initTree(Integer[] nodes) {
        //广度优先遍历
        Queue<Node> queue = new LinkedList<>();
        int level = 0;
        queue.add(root = new Node(nodes[0]));
        while(!queue.isEmpty()) {
            level++;
            int len = queue.size();
            for (int i = 0; i < len; i++) {
                Node node = queue.poll();
                //转换成数组对应下标
                int index = (int)Math.pow(2,level) - 1 + 2 * i;
                //判断越界
                if(index > nodes.length - 1) return root;
                Integer left = nodes[index];
                //生成左子树
                if(left == null) node.left =  null;
                else queue.add(node.left = new Node(left));
                //同上
                if(index + 1 > nodes.length -1) return root;
                Integer right = nodes[index+1];
                if(right == null) node.right = null;
                else queue.add(node.right = new Node(right));
            }
        }
        return root;
    }

    //先序遍历递归
    public void preOrder(Node root) {
        System.out.println(root.data + " ");
        preOrder(root.left);
        preOrder(root.right);
    }

    //先序遍历非递归
    public void preOrder() {
        Stack<Node> stack = new Stack<Node>();
        Node node = root;
        while(!stack.isEmpty() || node != null) {
            if(node != null) {
                stack.add(node);
                System.out.print(node.data + " ");
                node = node.left;
            } else {
                node = stack.pop();
                node  = node.right;
            }
        }
    }

    //中序遍历递归
    public void inOrder(Node root) {
        inOrder(root.left);
        System.out.print(root.data + " ");
        inOrder(root.right);
    }

    //中序遍历非递归
    public void inOrder() {
        Stack<Node> stack = new Stack<Node>();
        Node node = root;
        while(!stack.isEmpty() || node != null) {
            if(node != null) {
                stack.push(node);
                node = node.left;
            } else {
                node = stack.pop();
                System.out.print(node.data + " ");
                node = node.right;
            }
        }
    }

    //后序遍历递归
    public void postOrder(Node localRoot) {
        postOrder(localRoot.left);
        postOrder(localRoot.right);
        System.out.print(localRoot.data + " ");
    }

    //后序遍历非递归
    public void postOrder() {
        Stack<Node> s = new Stack<Node>();
        Node current;   //当前结点
        Node pre = null;    //前一次访问的结点
        s.push(this.root);
        while(!s.isEmpty()) {
            current = s.peek();
            if((current.left == null && current.right == null) ||
                    (pre != null && ( pre == current.left || pre == current.right))) {
                System.out.print(current.data + " ");  //如果当前结点没有孩子结点或者孩子节点都已被访问过
                s.pop();
                pre = current;
            } else {
                if(null != current.right) s.push(current.right);
                if(null != current.left) s.push(current.left);
            }
        }
    }

    //层序遍历
    public List<List<Integer>> BinaryTreeLevelOrderTraversal(Node root) {
        if(root == null) return new ArrayList<>();
        Queue<Node> queue = new LinkedList<>();
        List<List<Integer>> result = new ArrayList<>();
        queue.add(root);
        while(!queue.isEmpty()) {
            int count = queue.size();
            List<Integer> list = new ArrayList<>();
            while(count > 0){
                Node node = queue.poll();
                list.add(node.data);
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
                count--;
            }
            result.add(list);
        }
        return result;
    }

    //根据后序遍历和中序遍历生成树
    public void initTree(int[] preOrder,int[] inOrder) {
        this.root = this.initTree(preOrder,0,preOrder.length-1,inOrder,0,inOrder.length-1);
    }

    public Node initTree(int[] preOrder,int start1,int end1,int[] inOrder,int start2,int end2) {
        if(start1 > end1 || start2 > end2) return null;
        int rootData = preOrder[start1];
        Node head = new Node(rootData);
        int rootIndex = findIndexInArray(inOrder,rootData,start2,end2);
        int offSet = rootIndex - start2 -1;
        Node left = initTree(preOrder,start1+1,start1+1+offSet,inOrder,start2,start2+offSet);
        Node right = initTree(preOrder,start1+offSet+2,end1,inOrder,rootIndex+1,end2);
        head.left = left;
        head.right = right;
        return head;
    }

    public int findIndexInArray(int[] a,int x,int begin,int end) {
        for (int i = begin; i <= end; i++) {
            if(a[i] == x) return i;
        }
        return -1;
    }

    public void minDepth(Node root) {
        //见 Minimum Depth of Binary Tree 类
    }

    public void maxDepth(Node root) {
        //见 Maximum Depth of Binary Tree 类
    }
}

验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

  • 节点的左子树只包含小于当前节点的数。
  • 节点的右子树只包含大于当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

输入:
    2
   / \
  1   3
输出: true

示例 2:

输入:
    5
   / \
  1   4
     / \
    3   6
输出: false

解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。

:
方法1.中序遍历 查看当前节点是否大于前继节点(是否是升序)
方法2.递归,判断左子树最大值小于根节点,右子树最小值大于根节点

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    double last = -Double.MAX_VALUE;
    public boolean isValidBST(TreeNode root) {
        if (root == null) {
            return true;
        }
        if (isValidBST(root.left)) {
            if (last < root.val) {
                last = root.val;
                return isValidBST(root.right);
            }
        }
        return false;
    }
}

二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 1:

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。

示例 2:

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5

解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
说明:
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉树中。

:
方法1.若数据结构中存在父节点,公共祖先转化成求第一个相交节点 见Intersection_of_Two_Linked_Lists
方法2.递归左右子树 找到p或者q则返回 若一个节点左右子树都含p或q 那么那个节点就是公共祖先

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
   public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q) return root;
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        //WRONG:return left == null ? right : right == null ? null : root;
        return left != null && right != null ? root : left != null ? left : right;
    }
}

二叉树的层次遍历

给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]

:
方法1:BFS Queue
方法2:DFS 直接放入到对应层次的数组中

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root == null) return new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> result = new ArrayList<>();
        queue.add(root);
        while(!queue.isEmpty()) {
            int count = queue.size();
            List<Integer> list = new ArrayList<>();
            while(count > 0){
                TreeNode node = queue.poll();
                list.add(node.val);
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
                count--;
            }
            result.add(list);
        }
        return result;
    }
}

二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。

:
方法1.递归 计算左节点深度和右节点深度
方法2.BFS 判断是否是叶子节点
方法3.DFS 更新层数和min

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public 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;
    }
}

public int maxDepth(TreeNode root) {
        if(root == null) return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        int level = 0;
        while(!queue.isEmpty()) {
            level++;
            int count = queue.size();
            while(count > 0){
                TreeNode node = queue.poll();
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
                count--;
            }
        }
        return level;
    }

二叉树的最小深度

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明: 叶子节点是指没有子节点的节点。

示例:

给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回它的最小深度 2.

:
方法1.递归 计算左节点深度和右节点深度
方法2.BFS 判断是否是叶子节点
方法3.DFS 更新层数和min

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int minDepth(TreeNode root) {
        if(root == null) return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        int level = 1;
        while(!queue.isEmpty()) {
            int count = queue.size();
            while(count > 0){
                TreeNode node = queue.poll();
                if(node.left == null && node.right == null) return level;
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
                count--;
            }
            level ++;
        }
        return level;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_37873426/article/details/89417702