首页 > 代码库 > 三、二叉树

三、二叉树

一、递归思想:递归的基本思想是把规模大的问题转化为规模小的相似的子问题来解决。在函数实现时,因为解决大问题的方法和解决小问题的方法往往是同一个方法,所以就产生了函数调用它自身的情况。另外这个解决问题的函数必须有明显的结束条件,这样就不会产生无限递归的情况了。(http://www.nowamagic.net/librarys/veda/detail/2314)

  1)遍历:结果在调用时作为参数传递;从顶到下的过程

  2)分治:结果在返回值里,不在调用中作为参数传递,从下到上(有递、无归)

  同:递归思想

90%二叉数问题都可分治解决

二叉树问题:

1、树形分析时间复杂度计算=树中节点个数*每个节点的处理时间

2、二叉树结构:

技术分享
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
View Code

3、二叉树遍历:

递归:

1)前:跟-左-右

技术分享
public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: Preorder in ArrayList which contains node values.
     */
    public ArrayList<Integer> preorderTraversal(TreeNode root) {
        // write your code here
        //recursion
        ArrayList<Integer> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        traverse(root,res);
        return res;
    }
    private void traverse(TreeNode root, ArrayList<Integer> res) {
        if (root == null) {
            return;
        }
        res.add(root.val);
        traverse(root.left, res);
        traverse(root.right, res);
    }
}
View Code

2中:左-根-右

技术分享
public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: Inorder in ArrayList which contains node values.
     */
    public ArrayList<Integer> inorderTraversal(TreeNode root) {
        // write your code here
        ArrayList<Integer> result = new ArrayList<>();
        traverse(root, result);
        return result;
    }
    private void traverse(TreeNode root, ArrayList<Integer> result) {
        if (root == null) {
            return;
        }
        traverse(root.left, result);
        result.add(root.val);
        traverse(root.right,result);
    }
}
View Code

3)后: 左- 右-中

技术分享
public ArrayList<Integer> postorderTraversal(TreeNode root) {
    ArrayList<Integer> result = new ArrayList<Integer>();

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

    result.addAll(postorderTraversal(root.left));
    result.addAll(postorderTraversal(root.right));
    result.add(root.val);

    return result;   
}
View Code

 

非递归

前:2遍,带刷,not ac : root 和 treeNode 分错

技术分享
public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: Preorder in ArrayList which contains node values.
     */
    public ArrayList<Integer> preorderTraversal(TreeNode root) {
        // write your code here
        //no - recusion
        ArrayList<Integer> result = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if (root == null) {
            return result;
        }
        stack.push(root);
        while (!stack.empty()) {
            TreeNode treeNode = stack.pop();
            result.add(treeNode.val);
            if (treeNode.right != null) {
                stack.push(treeNode.right);
            }
            if (treeNode.left != null) {
                stack.push(treeNode.left);
            }
        }
        return result;
    }
}
View Code

中:

技术分享
public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: Inorder in ArrayList which contains node values.
     */
    public ArrayList<Integer> inorderTraversal(TreeNode root) {
        // write your code here
        ArrayList<Integer> result = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while (node != null || !stack.empty()) {
            while (node != null) {//遍历到最左边
                stack.push(node);
                node = node.left;
            }
            node = stack.peek();//取出栈顶但不删除
            stack.pop();
            result.add(node.val);//把最左边的节点加入结果
            node = node.right;//该节点有右叶子吗?
        }
        return result;
    }
}
View Code

后:not ac, 右回的时候忘了pop()

技术分享
public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: Postorder in ArrayList which contains node values.
     */
    public ArrayList<Integer> postorderTraversal(TreeNode root) {
        // write your code here
        ArrayList<Integer> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        TreeNode cur = root;
        TreeNode pre = null;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.empty()) {
            cur = stack.peek();
            // trarve up the tree, 深度递归
            if (pre == null || pre.left == cur || pre.right == cur) {
                if (cur.left != null) {
                    stack.push(cur.left);
                } else if (cur.right != null){
                    stack.push(cur.right);
                }
            } else if (cur.left == pre){//从左面回溯的
                if (cur.right != null) {
                    stack.push(cur.right);
                }
            } else {//从右边回溯的
                result.add(cur.val);
                stack.pop();
            }
            pre = cur;
        }
        return result;
    }
}
View Code

 

 4、二叉树的最大深度:

(1) 分治法:ac

技术分享
public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: An integer.
     */
    private int depth;
    public int maxDepth(TreeNode root) {
        // write your code here
        if (root == null) {
            return 0;
        }
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        depth = Math.max(left, right) + 1;
        return depth;
    }
}
View Code

(2)travese:not ac :curdepth是结果,被传递,不断变化的

技术分享
public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: An integer.
     */
    private int depth;
    public int maxDepth(TreeNode root) {
        // write your code here
        depth = 0;
        helper(root, 1);
        return depth;
    }
    private void helper (TreeNode root, int curdepth) {
        if (root == null) {
            return;
        }
        if (curdepth > depth) {
            depth = curdepth;
        }
        helper(root.left, curdepth + 1);
        helper(root.right, curdepth + 1);
    }
}
View Code

5、Binary Tree Paths(http://www.lintcode.com/en/problem/binary-tree-paths/):根节点到叶子节点的路径

一遍,带看,ac:

分治法

技术分享
public class Solution {
    /**
     * @param root the root of the binary tree
     * @return all root-to-leaf paths
     */
    public List<String> binaryTreePaths(TreeNode root) {
        // Write your code here
        //分治法
        List<String> paths = new ArrayList<>();
        if (root == null) {
            return paths;
        }
        List<String> leftPaths = binaryTreePaths(root.left);
        List<String> rightPaths = binaryTreePaths(root.right);
        for (String path : leftPaths) {
            paths.add(root.val + "->" + path);
        }
        for (String path : rightPaths) {
            paths.add(root.val + "->" + path);
        }
        //root is a leaf
        if (paths.size() == 0) {
            paths.add("" + root.val);
        }
        return paths;
    }
}
View Code
遍历法:not ac, 节点.val,String.valueOf()不懂
技术分享
public class Solution {
    /**
     * @param root the root of the binary tree
     * @return all root-to-leaf paths
     */
    public List<String> binaryTreePaths(TreeNode root) {
        // Write your code here
        //遍历
        List<String> results = new ArrayList<>();
        if (root == null) {
            return results;
        }
        helper(root, String.valueOf(root.val), results);
        return results;
    }
    private void helper(TreeNode root, String path, List<String> results) {
        if (root == null) {
            return;
        }
        if (root.left == null && root.right == null) {
            results.add(path);
            return;
        }
        if (root.left != null) {
            helper(root.left, path + "->" + String.valueOf(root.left.val), results);
        }
        if (root.right != null) {
            helper(root.right, path + "->" + String.valueOf(root.right.val), results);
        }
    }
}
View Code

 

6、Minimum Subtree( http://www.lintcode.com/en/problem/minimum-subtree/):

not ac : helper()返回错误,sum而不是subtreesum,sum下次还有继续用;

思路:我们可以这样考虑:对于每一个节点,
1. 如果它是空节点,那么就返回0
2. 如果它有左子数,那么加上左子树的和
3. 如果它有右子树,那么加上右子树的和
简单来说,对于任何一个节点,我们不去考虑它下面还有多少儿子,只是考虑和它直接接触的左儿子和右儿子(如果存在的话)。如果到这个节点为止的和小于之前的和,那么就更新最小和,以及要回答的节点。

技术分享
public class Solution {
    /**
     * @param root the root of binary tree
     * @return the root of the minimum subtree
     */
    private TreeNode subtree = null;
    private int subtreeSum = Integer.MAX_VALUE;
    public TreeNode findSubtree(TreeNode root) {
        //Divserse + traverse
        helper(root);
        return subtree;
    }
    private int helper(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int sum = helper(root.left) + helper(root.right) + root.val;
        if (sum < subtreeSum) {
            subtreeSum = sum;
            subtree = root;
        }
        return sum;
    }
}
View Code

 7、判断是否平衡二叉树:

notac :class 要小写

第一种:BOttom -UP o(n),o(n),當左子樹不平衡時,沒有必要再對右子樹求深度,要馬上 return -1,不可以把兩個判斷式寫在一起。

ResultType:class ResultType { int var1, var2; }---创建一个type类,一个默认方法包含,boolean,maxdepth, type helper():当子树不是,根不是,空是,返回一个new type();

技术分享
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) {
        // write your code here
        return helper(root).isBalanced;
    }
    private ResultType helper(TreeNode root) {
        if (root == null) {//root 空,是平衡二叉树
            return new ResultType (true, -1);
        }
        ResultType left = helper(root.left);
        ResultType right = helper(root.right);
        //leaf is not 
        if (!left.isBalanced || !right.isBalanced) {
            return new ResultType(false, -1);
        }
        //root is not
        if (Math.abs(left.maxDepth - right.maxDepth) > 1) {
            return new ResultType(false, -1);
        }
        return new ResultType(true, Math.max(left.maxDepth, right.maxDepth) + 1);
    }
}
View Code

第二种:Top-down Recursion Approach;Time Complexity : t:O(n^2),s:o(n),但是 maxDepth() 會一直重複呼叫導致有重複計算的部分。

构建int maxdepth函数,返回值判断 maxdepth != -1为真吗。

技术分享
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) {
        // write your code here
        return maxDepth(root) != -1;
    }
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        //leaf is not 
        if (left == -1 || right == -1) {
            return -1;
        }
        //root is not
        if (Math.abs(left - right) > 1) {
            return -1;
        }
        return Math.max(left, right) + 1;
    }
}
View Code

8、Subtree with Maximum Average  http://www.lintcode.com/problem/subtree-with-maximum-average/ 

遍历+分治:遍历:从上往下递,分治从下往上的归,求resultsum.

技术分享
public class Solution {
    /**
     * @param root the root of binary tree
     * @return the root of the maximum average of subtree
     */
private class ResultType {
    int sum;
    int size;
    public ResultType(int sum, int size) {
        this.sum = sum;
        this.size = size;
    }
}
    private TreeNode subtree = null;
    private ResultType subtreeSum = null;
    public TreeNode findSubtree2(TreeNode root) {
        // Write your code here
        helper(root);
        return subtree;
    }
    public ResultType helper(TreeNode root) {
        if (root == null) {
            return new ResultType (0, 0);
        }
        ResultType left = helper(root.left);
        ResultType right = helper(root.right);
        ResultType result = new ResultType(left.sum + right.sum + root.val,
        left.size + right.size + 1);
        if (subtree == null || subtreeSum.sum * result.size < result.sum * subtreeSum.size) {
            subtree = root;
            subtreeSum = result;
        }
        return result;
    }
}
View Code

9、Flattern Binary Tree to Linked List http://www.lintcode.com/problem/flatten-binary-tree-to-linked-list/

1)、Non-Recursion

技术分享
public class Solution {
    /**
     * @param root: a TreeNode, the root of the binary tree
     * @return: nothing
     */
    public void flatten(TreeNode root) {
        // write your code here
        // no - curision
        if (root == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.empty()) {
            TreeNode node = stack.pop();
            if (node.right != null) {
                stack.push(node.right);
            }
            if (node.left != null) {
                stack.push(node.left);
            }
            //connect:当前节点左制空,右边为堆栈弹出的节点
            node.left = null;
            if (stack.empty()) {
                node.right = null;
            } else {
                node.right = stack.peek();
            }
        }
    }
}
View Code

2)、traverse

查看http://www.jiuzhang.com/solutions/flatten-binary-tree-to-linked-list/

blog:http://blog.csdn.net/linhuanmars/article/details/23717703   递归思路很详细:每次把pre 节点左节点制空,右节点置为当前节点。o(n),o(logn)

10、Lowest Common Ancestor http://www.lintcode.com/problem/lowest-common-ancestor/

前提:A,B都在树中

1)divide + conquer :o(n)

技术分享
public class Solution {
    /**
     * @param root: The root of the binary search tree.
     * @param A and B: two nodes in a Binary.
     * @return: Return the least common ancestor(LCA) of the two nodes.
     */
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) {
        // write your code here
        //divide + conquer o(n)
        if (root == null || root == A || root == B) {
            return root;
        }
        //divide
        TreeNode left = lowestCommonAncestor(root.left, A, B);
        TreeNode right = lowestCommonAncestor(root.right, A, B);
        //conquer
        if (left != null && right != null) {
            return root;
        }
        if (left != null) {
            return left;
        }
        if (right != null) {
            return right;
        }
        return null;
    }
}
View Code

缺陷 无法分别root 是其中之一,而另一个不在树种

2)优化,可解决其中之一不在该树中

11、Binary Tree Longest Consecutive Sequence http://www.lintcode.com/problem/binary-tree-longest-consecutivesequence/

技术分享
public class Solution {
    /**
     * @param root the root of binary tree
     * @return the length of the longest consecutive sequence path
     */
    public int longestConsecutive(TreeNode root) {
        //tranverse + divide
        return helper(root, null, 0);
    }
    public int helper(TreeNode root, TreeNode parent, int lengthwithoutroot) {
        if (root == null) {
            return 0;
        }
        int length = (parent != null && parent.val + 1 == root.val) ? 
                    lengthwithoutroot + 1 : 1;
        int left = helper(root.left, root, length);
        int right = helper(root.right, root, length);
        return Math.max(length, Math.max(left,right));
    }
}
View Code

12、Binary Tree Path Sum I http://www.lintcode.com/problem/binary-tree-path-sum/   从根出发

not ac:is leaf 

技术分享
public class Solution {
    /**
     * @param root the root of binary tree
     * @param target an integer
     * @return all valid paths
     */
    public List<List<Integer>> binaryTreePathSum(TreeNode root, int target) {
        // Write your code here
        List<List<Integer>> results = new ArrayList<>();
        if (root == null) {
            return results;
        }
        List<Integer> path = new ArrayList<Integer>();
        path.add(root.val);
        helper(root, root.val, path, results, target);
        return results;
    }
    private void helper(TreeNode root, int sum,
                        List<Integer> path, 
                        List<List<Integer>> results,
                        int target) {
        //meet leaf                    
        if (root.left == null && root.right == null) {
            if (sum == target) {
                results.add(new ArrayList<Integer>(path));
            }
        }
        //go left
        if (root.left != null) {
            path.add(root.left.val);
            helper(root.left, sum + root.left.val, path, results, target);
            path.remove(path.size() - 1);
        }
        //go right
        if (root.right != null) {
            path.add(root.right.val);
            helper(root.right, sum + root.right.val, path, results, target);
            path.remove(path.size() - 1);
        }
        
                        }
}
View Code

13、Binary Tree Path SumII  http://www.lintcode.com/problem/binary-tree-path-sum-ii/  任意节点出发,但是层级递增的

技术分享
    public List<List<Integer>> binaryTreePathSum2(TreeNode root, int target) {
        // Write your code here
        List<List<Integer>> results = new ArrayList<>();
        if (root == null) {
            return results;
        }
        List<Integer> path = new ArrayList<>();
        helper(root, target, path, results, 0);
        return results;
    }
    private void helper(TreeNode head, int sum,List<Integer> path,
                        List<List<Integer>> results, int level) {
        if (head == null) {
            return;
        }
        int temp = sum;
        path.add(head.val);
        for (int i = level; i >= 0; i--) {
            temp -= path.get(i);
            if (temp == 0) {
                List<Integer> tmp = new ArrayList<Integer> ();
                for (int j = i; j <= level; j++) {
                    tmp.add(path.get(j));
                }
                results.add(tmp);
            }
        }
        helper(head.left, sum, path, results, level + 1);
        helper(head.right, sum, path, results, level + 1);
        path.remove(path.size() - 1);
                        }
}
View Code

14.Binary Tree Path SumIII  

技术分享
public class Solution {
    /**
     * @param root the root of binary tree
     * @param target an integer
     * @return all valid paths
     */
    public List<List<Integer>> binaryTreePathSum3(ParentTreeNode root, int target) {
        // Write your code here
        List<List<Integer>> results = new ArrayList<>();
        dfs(root, target, results);
        return results;
    }
    private void dfs(ParentTreeNode root, int target, List<List<Integer>> results) {
        if (root == null) {
            return;
        }
        List<Integer> path = new ArrayList<Integer>();
        findSum(root, null, path, results, target);
        dfs(root.left, target, results);
        dfs(root.right, target, results);
    }
    private void findSum(ParentTreeNode root, ParentTreeNode father,
                        List<Integer> path, List<List<Integer>> results, int target) {
        path.add(root.val);
        target -= root.val;
        if (target == 0) {
            List<Integer> tmp = new ArrayList<Integer>();
            Collections.addAll(tmp, new Integer [path.size()]);
            Collections.copy(tmp, path);
            results.add(tmp);
        }
        if (root.parent != null && root.parent != father) {
            findSum(root.parent, root, path, results, target);
        }
        if (root.left != null && root.left != father) {
            findSum(root.left, root, path, results, target);
        }
        if (root.right != null && root.right != father) {
            findSum(root.right, root, path, results, target);
        }
        path.remove(path.size() - 1);
    }
}
View Code

三、二叉查找树:

性质:1.左子树小于跟

从定义出发: ? 左子树都比根节点小  left <= root

       ? 右子树都不小于根节点 root < right

从效果出发: ? 中序遍历 in-order traversal 是“不下降”序列

       ? 如果一棵二叉树的中序遍历不是“不下降”序列,则一定不是BST

       ? 如果一棵二叉树的中序遍历是不下降,也未必是BST

 

1、Validate Binary Search Tree http://www.lintcode.com/problem/validate-binary-search-tree/ (都是严格小于和大于)

方法一:一个变量last存放当上一个节点的值,中序遍历二叉树,比较当前节点和last,但无法处理  【10,#,20】和【10,20】的情况 ,只能当满足 root.left < root <root.right适用

not ac :int ---long ,对当前节点判断应该是《=

技术分享
public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: True if the binary tree is BST, or false
     */
    public long last = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        // write your code here
        if (root == null) {
            return true;
        }
        //检查左子树
        if (!isValidBST(root.left)) {
            return false;
        }
        //检查当前节点
        if (root.val <= last) {
            return false;
        }
        last = root.val;
        //检查右子树
        if (!isValidBST(root.right)) {
            return false;
        }
        return true;
    }
}
View Code

 

方法二:最大、最小法:min = INTEGER.MIN,max =INTEGER.MAX,每个节点都进行判断  cur.left <= cur<cur.right当进入左子树,更新min,当进入右子树更新max

not ac : int 换为 long

技术分享
public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: True if the binary tree is BST, or false
     */
    private long min = Long.MIN_VALUE;
    private long max = Long.MAX_VALUE;
    public boolean isValidBST(TreeNode root) {
        // write your code here
        return isValidhelper(root, min, max);
    }
    private boolean isValidhelper(TreeNode root, long min, long max) {
        if (root == null) {
            return true;
        }
        if (root.val <= min || root.val >= max) {
            return false;
        }
        if (!isValidhelper(root.left, min, root.val) 
        || !isValidhelper(root.right, root.val, max)){
            return false;
        }
        return true;
    }
}
View Code

 2、Convert Binary Search Tree to Doubly Linked List    http://www.lintcode.com/problem/convert-binary-search-tree-to-do ubly-linked-list/

 

三、二叉树