首页 > 代码库 > 三、二叉树
三、二叉树
一、递归思想:递归的基本思想是把规模大的问题转化为规模小的相似的子问题来解决。在函数实现时,因为解决大问题的方法和解决小问题的方法往往是同一个方法,所以就产生了函数调用它自身的情况。另外这个解决问题的函数必须有明显的结束条件,这样就不会产生无限递归的情况了。(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; * } * }
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); } }
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); } }
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; }
非递归
前: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; } }
中:
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; } }
后: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; } }
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; } }
(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); } }
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; } }
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); } } }
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; } }
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); } }
第二种: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; } }
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; } }
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(); } } } }
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; } }
缺陷 无法分别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)); } }
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); } } }
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); } }
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); } }
三、二叉查找树:
性质: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; } }
方法二:最大、最小法: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; } }
2、Convert Binary Search Tree to Doubly Linked List http://www.lintcode.com/problem/convert-binary-search-tree-to-do ubly-linked-list/
三、二叉树