• 二叉树基础


    一、二叉树深度优先遍历

    只介绍先序遍历:

    (1) 第一种方法是使用stack的结构

    (2) 主要要理解后面的分治法

    Version 0: Non-Recursion (Recommend)
    /**
     * Definition for binary tree
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    public class Solution {
        public List<Integer> preorderTraversal(TreeNode root) {
            Stack<TreeNode> stack = new Stack<TreeNode>();
            List<Integer> preorder = new ArrayList<Integer>();
            
            if (root == null) {
                return preorder;
            }
            
            stack.push(root);
            while (!stack.empty()) {
                TreeNode node = stack.pop();
                preorder.add(node.val);
                if (node.right != null) {
                    stack.push(node.right);
                }
                if (node.left != null) {
                    stack.push(node.left);
                }
            }
            
            return preorder;
        }
    }
    
    //Version 1: Traverse
    public class Solution {
        public ArrayList<Integer> preorderTraversal(TreeNode root) {
            ArrayList<Integer> result = new ArrayList<Integer>();
            traverse(root, result);
            return result;
        }
        // 把root为跟的preorder加入result里面
        private void traverse(TreeNode root, ArrayList<Integer> result) {
            if (root == null) {
                return;
            }
    
            result.add(root.val);
            traverse(root.left, result);
            traverse(root.right, result);
        }
    }
    
    //Version 2: Divide & Conquer
    public class Solution {
        public ArrayList<Integer> preorderTraversal(TreeNode root) {
            ArrayList<Integer> result = new ArrayList<Integer>();
            // null or leaf
            if (root == null) {
                return result;
            }
    
            // Divide
            ArrayList<Integer> left = preorderTraversal(root.left);
            ArrayList<Integer> right = preorderTraversal(root.right);
    
            // Conquer
            result.add(root.val);
            result.addAll(left);
            result.addAll(right);
            return result;
        }
    }

    二、分治法

    三个例子:

      归并排序

      快速排序

      大多数的二叉树问题

    归并排序和快速排队都是典型的分治法。

    归并排序:强调先局部有序,再归并为整体有序. 最差时间复杂度和平均复杂度都是log(n)*n,但是有问题就是在归并的时候需要额外的空间,同时它还是一个稳定(什么是稳定,相同元素的位置是否需要移动)的排序算法。

    快速排序:强调先整体有序,再partition为局部有序,最差情况是n*n,平均复杂度是log(n)*n,不需要额外空间,需要swap操作,是一个不稳定的排序算法。

    数学归纳法是成立的,一切都是建立数学归纳法是成立以及空集存在的可能性上建立的。

    二叉树问题:

    (1) 最大深度:

      depth(TreeNode) = max(depth(left), depth(right))+1

    (2) 是否是平衡树?

    是平衡树:

      leftChild是平衡树

      rightChild是平衡树

      | depth(leftChild) - depth(rightChild) | <1

    class ResultType {
        public boolean isBalanced;
        public int maxDepth;
        public ResultType(boolean isBalanced, int maxDepth) {
            this.isBalanced = isBalanced;
            this.maxDepth = maxDepth;
        }
    }
    public class Solution {
        /**
         * @param root: The root of binary tree.
         * @return: True if this Binary tree is Balanced, or false.
         */
        public boolean isBalanced(TreeNode root) {
            return helper(root).isBalanced;
        }
        
        private ResultType helper(TreeNode root) {
            if (root == null) {
                return new ResultType(true, 0);
            }
            
            ResultType left = helper(root.left);
            ResultType right = helper(root.right);
            
            // subtree not balance
            if (!left.isBalanced || !right.isBalanced) {
                return new ResultType(false, -1);
            }
            
            // root not balance
            if (Math.abs(left.maxDepth - right.maxDepth) > 1) {
                return new ResultType(false, -1);
            }
            
            return new ResultType(true, Math.max(left.maxDepth, right.maxDepth) + 1);
        }
    }

    (3) 最近公共祖先问题

    问题描述:给2个节点n1 n2 (n1,n2都存在),寻找二者最近的公共祖先.

    find(root, n1, n2)

    分治法,从根出发,自顶向下,从左右2个子树上去寻找.

    先考虑单子树的情况:

    • 如果root是n1, n2一定存在的话,肯定在n1下面,直接返回root
    • root是n2同理
    • 如果root == null, 表明这个子树找不到了返回null

    合并2个子树的寻找结果 leftResult和rightResult.

    如果leftResult非空,表明至少出现一个或者出现2个.

    同理,如果rightResult非空,表明至少出现一个或者出现2个.

    因此:

    如果都非空,表示一边一个,返回root

    如果一边为空,另一边非空,返回非空的那个

    如果都为空,没有找到? 和假设不合,不考虑

    代码如下:

    // 在root为根的二叉树中找A,B的LCA:
        // 如果找到了就返回这个LCA
        // 如果只碰到A,就返回A
        // 如果只碰到B,就返回B
        // 如果都没有,就返回null
    
    
        /**
         * 这里有个假设, node1和node2都必须存在. 假如不存在下面的方法是有问题的.
         *
         * @param root  以root为搜索基础节点
         * @param node1 要寻找的node1
         * @param node2 要寻找的node2
         * @return 二者的最近公共祖先
         */
        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode node1, TreeNode node2) {
            if (root == null) {
                return null;
            }
    
            if (root == node1) {
                return node1;
            }
    
            if (root == node2) {
                return node2;
            }
    
            TreeNode leftResult = lowestCommonAncestor(root.left, node1, node2);
            TreeNode rightResult = lowestCommonAncestor(root.left, node1, node2);
            if (leftResult == null && rightResult == null) {
                return null;
            } else if (leftResult != null & rightResult != null) {
                return root;
            } else if (leftResult == null && rightResult != null) {
                return rightResult;
            } else {
                return leftResult;
            }
        }

     总结使用分治法解决的大致代码模板:

    public class Solution {
        public void traverse(TreeNode root) {
            if (root == null) {
                return;
            }
            // do something with root
            traverse(root.left);
            // do something with root
            traverse(root.right);
            // do something with root
        }
    }
    
    
    Tempate 2: Divide & Conquer
    
    public class Solution {
        public ResultType traversal(TreeNode root) {
            // null or leaf
            if (root == null) {
                // do something and return;
            }
            
            // Divide
            ResultType left = traversal(root.left);
            ResultType right = traversal(root.right);
            
            // Conquer
            ResultType result = Merge from left and right.
            return result;
        }
    }

    三、BFS基础

    三种方式:

    2个队列

    1个队列 + Dummy Node

    1个队列 (best)

     
    public class Solution {
        /**
         * @param root: The root of binary tree.
         * @return: buttom-up level order a list of lists of integer
         */
        public ArrayList<ArrayList<Integer>> levelOrderBottom(TreeNode root) {
            ArrayList<ArrayList<Integer>> result = new ArrayList<>();
            if (root == null) {
                return result;
            }
            Queue<TreeNode> queue = new LinkedList<TreeNode>();
            queue.offer(root);
            
            while (!queue.isEmpty()) {
                int size = queue.size();
                ArrayList<Integer> level = new ArrayList<>();
                for (int i = 0; i < size; i++) {
                    TreeNode head = queue.poll();
                    level.add(head.val);
                    if (head.left != null) {
                        queue.offer(head.left);
                    }
                    if (head.right != null) {
                        queue.offer(head.right);
                    }
                }
                result.add(level);
            }
            
            Collections.reverse(result);
            return result;
        }
    }

    四、二叉搜索树

    左子树比根节点小, 且右子树比根节点大.

    (1) 判断是否是bst

    (2) range query

    (3) remove node

    (4) Iterator

  • 相关阅读:
    c#过滤所有换行符和多余空格
    个人整理网站外链专用
    C++操作符的优先级
    winform下richtextbox 特定字符颜色的改变
    触摸屏网站制作的小细节
    DEDECMS 批量替换alt为空的文章为文章标题的MYSQL语句
    天涯海客邮件搜索群发大师 使用说明
    天涯论坛自动回帖软件免费版使用说明
    c# winform窗口控件委托传参数的写法
    论坛自动回帖软件终于在多特软件站发布成功了
  • 原文地址:https://www.cnblogs.com/carl10086/p/6287576.html
Copyright © 2020-2023  润新知