几种常见的二叉树:
满二叉树 :除了叶子节点外,所有节点都有两个儿子,深度为 k 的满二叉树具有 2^k - 1 个节点。
完全二叉树 :若设二叉树的高度为h,除第h层外,其他各层 (1 ~ h -1)层节点都达到最大个数,第h层的叶子节点从左到右依次排列。
平衡二叉树(AVL) :是一棵平衡的二叉查找树。任何一个节点的左右两个儿子的高度差不超过1,并且其左右子树都是平衡二叉树。
二叉查找树(BST) : 左 < 根 < 右。(BST不一定是平衡二叉树)
遇到二叉树问题,就想想整棵树在该问题上的结果和左右子树在该问题上的结果之间的联系。
二叉树问题常常伴随着遍历出现,基本的就有前序遍历,中序遍历,后续遍历。三种遍历的实现分为递归实现和非递归实现,而递归实现又可以分为遍历法和分治法。区分遍历法可以简单想为遍历就是都是自己去做,而分治是分给自己的小弟去做。
一般分子二叉树问题都可以使用分治,就是无脑的先丢给左子树,然后无脑的丢给右子树,得到左右子树的结果之后再考虑根节点。
这里就先给出三种遍历的三种实现方法。前序遍历:根左右 中序遍历:左根右 后续遍历:左右根
前序遍历遍历法:
1 public ArrayList<Integer> preorderTraversal(TreeNode root) { 2 // write your code here 3 ArrayList<Integer> result = new ArrayList<Integer>(); 4 preorderHelp(result,root); 5 return result; 6 } 7 public void preorderHelp(ArrayList<Integer> result , TreeNode root) { 8 if (root == null) { 9 return; 10 } 11 result.add(root.val); 12 preorderHelp(result, root.left); 13 preorderHelp(result, root.right); 14 }
前序遍历非递归:
1 public ArrayList<Integer> preorderTraversal(TreeNode root) { 2 // write your code here 3 ArrayList<Integer> result = new ArrayList<Integer>(); 4 if (root == null) 5 return result; 6 Stack<TreeNode> stack = new Stack<TreeNode>(); 7 stack.push(root); 8 while(!stack.isEmpty()) { 9 TreeNode node = stack.pop(); 10 result.add(node.val); 11 if(node.right != null){ 12 stack.push(node.right); 13 } 14 if(node.left != null){ 15 stack.push(node.left); 16 } 17 } 18 return result; 19 }
前序遍历分治算法:
1 public ArrayList<Integer> preorderTraversal(TreeNode root) { 2 // write your code here 3 ArrayList<Integer> result = new ArrayList<Integer>(); 4 if (root == null) { 5 return result; 6 } 7 result.add(root.val); 8 ArrayList<Integer> left = preorderTraversal(root.left); 9 ArrayList<Integer> right = preorderTraversal(root.right); 10 result.addAll(left); 11 result.addAll(right); 12 return result; 13 }
中序遍历,后续遍历的分治算法和遍历算法与前序遍历的区别仅仅是添加的顺序不同。非递归算法有所区别。
中序遍历非递归:
1 public ArrayList<Integer> inorderTraversal(TreeNode root) { 2 // write your code here 3 ArrayList<Integer> result = new ArrayList<Integer>(); 4 TreeNode curNode = root; 5 Stack<TreeNode> stack = new Stack<TreeNode>(); 6 while (curNode != null || !stack.isEmpty()) { 7 while (curNode != null){ 8 stack.push(curNode); 9 curNode=curNode.left; 10 } 11 curNode = stack.peek(); 12 result.add(curNode.val); 13 stack.pop(); 14 curNode = curNode.right; 15 } 16 return result; 17 }
后续遍历非递归:
后续遍历的非递归算法还是有点难度的,主要是记录是从上往下遍历 还是从左往上遍历 还是从右往上遍历。使用两个Node prev和cur,使用这两个节点的关系来判断是上述三种情况的哪一种,只有在第三种情况下result中添加值。
1 public ArrayList<Integer> postorderTraversal(TreeNode root) { 2 // write your code here 3 ArrayList<Integer> result = new ArrayList<Integer>(); 4 Stack<TreeNode> stack = new Stack<TreeNode>(); 5 TreeNode cur = root; 6 TreeNode prev = null; 7 if (root == null) { 8 return result; 9 } 10 stack.push(root); 11 while (!stack.isEmpty()) { 12 cur = stack.peek(); 13 if (prev == null || prev.left == cur || prev.right == cur) { //traverse down the tree 14 if (cur.left != null) { 15 stack.push(cur.left); 16 } 17 else if (cur.right != null) { 18 stack.push(cur.right); 19 } 20 } 21 else if (cur.left == prev) {//traverse up the tree from the left 22 if (cur.right != null) { 23 stack.push(cur.right); 24 } 25 } 26 else { 27 result.add(cur.val); 28 stack.pop(); 29 } 30 prev = cur; 31 } 32 return result; 33 }
后续遍历非递归算法二,类似于前序遍历,先得到根右左到栈中,然后弹出。
1 public ArrayList<Integer> postorderTraversal(TreeNode root) { 2 // write your code here 3 ArrayList<Integer> result = new ArrayList<Integer>(); 4 Stack<TreeNode> stack = new Stack<TreeNode>(); 5 TreeNode cur = root; 6 TreeNode prev = null; 7 if (root == null) { 8 return result; 9 } 10 stack.push(root); 11 while (!stack.isEmpty()) { 12 cur = stack.peek(); 13 if (prev == null || prev.left == cur || prev.right == cur) { //traverse down the tree 14 if (cur.left != null) { 15 stack.push(cur.left); 16 } 17 else if (cur.right != null) { 18 stack.push(cur.right); 19 } 20 } 21 else if (cur.left == prev) {//traverse up the tree from the left 22 if (cur.right != null) { 23 stack.push(cur.right); 24 } 25 } 26 else { 27 result.add(cur.val); 28 stack.pop(); 29 } 30 prev = cur; 31 } 32 return result; 33 }
下面看看二叉树问题的无脑左右子树分治解决方案:
二叉树的最大深度
1 public int maxDepth(TreeNode root) { 2 // write your code here 3 if (root == null) 4 return 0; 5 int left = maxDepth(root.left); 6 int right = maxDepth(root.right); 7 return Math.max(left, right) + 1; 8 }
平衡二叉树
给定一个二叉树,确定它是高度平衡的。对于这个问题,一棵高度平衡的二叉树的定义是:一棵二叉树中每个节点的两个子树的深度相差不会超过1。
分治算法实现,这里需要注意的是分治的返回值有两个,以前遇到过用-1来代表子树不是平衡树的情况,觉得这种想法很好,其实不应该这样,这样带来了二义性的问题。代码还是要有利于阅读较好。
1 public boolean isBalanced(TreeNode root) { 2 // write your code here 3 return isBalancedHelp(root).isBalanced; 4 } 5 public ReturnType isBalancedHelp(TreeNode root) { 6 if(root == null) { 7 return new ReturnType(0 , true); 8 } 9 ReturnType left = isBalancedHelp(root.left); 10 ReturnType right = isBalancedHelp(root.right); 11 int leftDepth = left.depth; 12 int rightDepth = right.depth; 13 int curDepth = Math.max(left.depth, right.depth)+1; 14 if (left.isBalanced && right.isBalanced) { 15 if (Math.abs(leftDepth - rightDepth) <= 1) 16 return new ReturnType(curDepth, true); 17 } 18 return new ReturnType(curDepth , false); 19 } 20 class ReturnType { 21 int depth; 22 boolean isBalanced; 23 public ReturnType(int depth, boolean isBalanced) { 24 this.depth = depth; 25 this.isBalanced =isBalanced; 26 } 27 }
最近公共祖先
给定一棵二叉树,找到两个节点的最近公共父节点(LCA)。
最近公共祖先是两个节点的公共的祖先节点且具有最大深度。
假设给出的两个节点都在树中存在。
遇到这类面试题,首先问有没有指向父亲的指针,有的话就简单了,直接往上遍历到根节点,得到两条路径,然后查找第一个不同的。注意这里假设的是一定有CA。
递归程序在包含AB时就返回LCA,只包含A就返回A,只包含B就返回B,否则返回null。
1 public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) { 2 // write your code here 3 if (root == null || root == A || root == B) { 4 return root; 5 } 6 TreeNode left = lowestCommonAncestor(root.left, A, B); 7 TreeNode right = lowestCommonAncestor(root.right, A, B); 8 if (left != null && right!=null) { 9 return root; 10 } 11 if (left != null) { 12 return left; 13 } 14 if (right != null) { 15 return right; 16 } 17 return null; 18 }
最近公共祖先 II
给一棵二叉树和二叉树中的两个节点,找到这两个节点的最近公共祖先LCA
。
两个节点的最近公共祖先,是指两个节点的所有父亲节点中(包括这两个节点),离这两个节点最近的公共的节点。
每个节点除了左右儿子指针以外,还包含一个父亲指针parent
,指向自己的父亲。
1 public ParentTreeNode lowestCommonAncestorII(ParentTreeNode root, 2 ParentTreeNode A, 3 ParentTreeNode B) { 4 // Write your code here 5 if (root == null || root == A || root == B) { 6 return root; 7 } 8 HashSet<ParentTreeNode> hashSet = new HashSet<ParentTreeNode>(); 9 10 while (A != null) { 11 hashSet.add(A); 12 A = A.parent; 13 } 14 while (B != null) { 15 if (hashSet.contains(B)) { 16 return B; 17 } 18 B = B.parent; 19 } 20 return null; 21 }
最近公共祖先 III
给一棵二叉树和二叉树中的两个节点,找到这两个节点的最近公共祖先LCA。
两个节点的最近公共祖先,是指两个节点的所有父亲节点中(包括这两个节点),离这两个节点最近的公共的节点。
返回 null
如果两个节点在这棵树上不存在最近公共祖先的话。
注意事项
这两个节点未必都在这棵树上出现。
1 public TreeNode lowestCommonAncestor3(TreeNode root, TreeNode A, TreeNode B) { 2 // write your code here 3 return help(root, A, B).root; 4 } 5 public ResultType help(TreeNode root, TreeNode A, TreeNode B) { 6 if (root == null) { 7 return new ResultType(null, false, false); 8 } 9 ResultType left = help(root.left, A, B); 10 ResultType right = help(root.right, A, B); 11 if (left.root != null) { 12 return left; 13 } 14 if (right.root != null) { 15 return right; 16 } 17 if (root == A) { 18 if (root == B) { 19 return new ResultType(root, true, true); 20 } 21 if (left.containsB || right.containsB) { 22 return new ResultType(root, true, true); 23 } 24 else { 25 return new ResultType(null, true, false); 26 } 27 } 28 else if (root == B) { 29 if (left.containsA || right.containsA) { 30 return new ResultType(root, true, true); 31 } 32 else { 33 return new ResultType(null, false, true); 34 } 35 } 36 else { 37 if (left.containsA) { 38 if (right.containsB) { 39 return new ResultType(root, true, true); 40 } 41 else { 42 return new ResultType(null, true, false); 43 } 44 } 45 else if (left.containsB) { 46 if (right.containsA) { 47 return new ResultType(root, true, true); 48 } 49 else { 50 return new ResultType(null, false, true); 51 } 52 } 53 else { 54 if (right.containsA) { 55 return new ResultType(null, true, false); 56 } 57 else if (right.containsB) { 58 return new ResultType(null, false, true); 59 } 60 else { 61 return new ResultType(null, false, false); 62 } 63 64 } 65 } 66 } 67 class ResultType { 68 TreeNode root; 69 boolean containsA; 70 boolean containsB; 71 public ResultType (TreeNode root, boolean containsA, boolean containsB) { 72 this.root = root; 73 this.containsA = containsA; 74 this.containsB = containsB; 75 } 76 }
二叉树的最大路径和 II
给一棵二叉树,找出从根节点出发的路径中,和最大的一条。
这条路径可以在任何二叉树中的节点结束,但是必须包含至少一个点(也就是根了)。
注意节点值可能为负数。无脑分给左右儿子就行。
1 public int maxPathSum2(TreeNode root) { 2 // Write your code here 3 if (root == null) { 4 return Integer.MIN_VALUE; 5 } 6 int left = maxPathSum2(root.left); 7 int right = maxPathSum2(root.right); 8 return root.val+Math.max(0,Math.max(left, right)); 9 }
二叉树中的最大路径和
给出一棵二叉树,寻找一条路径使其路径和最大,路径可以在任一节点中开始和结束(路径和为两个节点之间所在路径上的节点权值之和)
1 public int maxPathSum(TreeNode root) { 2 // write your code here 3 return maxPathSumHelp(root).any2Any; 4 } 5 public ResultType maxPathSumHelp(TreeNode root) { 6 if (root == null) { 7 return new ResultType( 8 Integer.MIN_VALUE, Integer.MIN_VALUE 9 ); 10 } 11 ResultType leftRes = maxPathSumHelp(root.left); 12 ResultType rightRes = maxPathSumHelp(root.right); 13 int root2Any = root.val 14 + Math.max(0, Math.max(leftRes.root2Any,rightRes.root2Any)); 15 int any2Any = root.val + Math.max(0,leftRes.root2Any) 16 + Math.max(0,rightRes.root2Any); 17 18 any2Any = Math.max(any2Any, 19 Math.max(leftRes.any2Any, rightRes.any2Any) 20 ); 21 return new ResultType(root2Any, any2Any); 22 } 23 class ResultType { 24 int root2Any; 25 int any2Any; 26 public ResultType(int root2Any, int any2Any) { 27 this.root2Any = root2Any; 28 this.any2Any = any2Any; 29 } 30 }
二叉查找树BST
注意二叉查找树不一定是平衡的,所以其查找复杂度不一定就是O(logn)
TreeMap是BST+Balanced。其删除 插入 查找 min max ceil(x) floor(x)复杂度都是O(logn)
验证二叉查找树
注意必须是整个左子树都比我小,整个右子树都比我大。并不只是左右子节点满足条件就行
1 public boolean isValidBST(TreeNode root) { 2 // write your code here 3 if (root == null) 4 return true; 5 return isValidBSTHelp(root).isValid; 6 } 7 public ResultType isValidBSTHelp(TreeNode root) { 8 ResultType right; 9 ResultType left; 10 if (root.left == null && root.right == null) { 11 return new ResultType(true, root.val, root.val); 12 } 13 if (root.left == null) { 14 right = isValidBSTHelp(root.right); 15 if (right.isValid && root.val < right.min) { 16 return new ResultType(true, root.val, right.max); 17 } 18 return new ResultType(false, 0, 0); 19 } 20 if (root.right == null) { 21 left = isValidBSTHelp(root.left); 22 if (left.isValid && root.val > left.max) { 23 return new ResultType(true, left.min, root.val); 24 } 25 return new ResultType(false, 0, 0); 26 } 27 right = isValidBSTHelp(root.right); 28 left = isValidBSTHelp(root.left); 29 if (left.isValid && right.isValid) { 30 if (left.max < root.val && right.min > root.val) { 31 return new ResultType(true, left.min, right.max); 32 } 33 } 34 return new ResultType(false, 0, 0); 35 } 36 class ResultType { 37 boolean isValid; 38 int min; 39 int max; 40 public ResultType(boolean isValid, int min, int max) { 41 this.isValid = isValid; 42 this.min = min; 43 this.max = max; 44 } 45 }
同样的思路换一个方向,写出来的代码就漂亮许多。
1 public boolean isValidBST(TreeNode root) { 2 // write your code here 3 return isValidBSTHelp(root).isValid; 4 } 5 public ResultType isValidBSTHelp(TreeNode root) { 6 if (root == null) { 7 return new ResultType(true, Integer.MAX_VALUE,Integer.MIN_VALUE); 8 } 9 ResultType left = isValidBSTHelp(root.left); 10 ResultType right = isValidBSTHelp(root.right); 11 if (!left.isValid || !right.isValid) { 12 return new ResultType(false, 0, 0); 13 } 14 if (root.left != null && root.val <= left.max 15 || root.right !=null && root.val >= right.min) { 16 return new ResultType(false, 0, 0); 17 } 18 return new ResultType(true, 19 Math.min(root.val, left.min), 20 Math.max(root.val,right.max)); 21 }
二叉查找树迭代器
1 public class BSTIterator { 2 TreeNode root; 3 Stack<TreeNode> stack; 4 //@param root: The root of binary tree. 5 public BSTIterator(TreeNode root) { 6 // write your code here 7 this.root = root; 8 stack = new Stack<TreeNode>(); 9 TreeNode cur = root; 10 while(cur != null) { 11 stack.push(cur); 12 cur = cur.left; 13 } 14 } 15 16 //@return: True if there has next node, or false 17 public boolean hasNext() { 18 // write your code here 19 return !stack.isEmpty(); 20 } 21 22 //@return: return next node 23 public TreeNode next() { 24 // write your code here 25 TreeNode cur = stack.pop(); 26 TreeNode right = cur.right; 27 while (right != null) { 28 stack.push(right); 29 right = right.left; 30 } 31 return cur; 32 } 33 }
二叉树的层次遍历
1 public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) { 2 // write your code here 3 ArrayList<ArrayList<Integer>> results = new ArrayList<>(); 4 ArrayList<Integer> list; 5 if (root == null) 6 return results; 7 Queue<TreeNode> queue = new LinkedList<>(); 8 queue.offer(root); 9 while (!queue.isEmpty()) { 10 int size = queue.size(); 11 list = new ArrayList<>(); 12 for (int i = 0; i< size; i++) { 13 TreeNode cur = queue.peek(); 14 if (cur.left != null) { 15 queue.offer(cur.left); 16 } 17 if (cur.right != null) { 18 queue.offer(cur.right); 19 } 20 list.add(cur.val); 21 queue.poll(); 22 } 23 results.add(new ArrayList<>(list)); 24 } 25 return results; 26 }
二叉树查找树中序后继 ***
1 public TreeNode inorderSuccessor(TreeNode root, TreeNode p) { 2 // write your code here 3 if (root == null || p == null) { 4 return null; 5 } 6 if (root.val == p.val) { 7 TreeNode right = root.right; 8 while (right != null && right.left != null) { 9 right = right.left; 10 } 11 return right; 12 } 13 if (root.val > p.val) { 14 TreeNode left = inorderSuccessor(root.left, p); 15 if (left == null) { 16 return root; 17 } 18 return left; 19 } 20 return inorderSuccessor(root.right, p); 21 }
二叉树的路径和
给定一个二叉树,找出所有路径中各节点相加总和等于给定 目标值
的路径。
一个有效的路径,指的是从根节点到叶节点的路径。
1 public List<List<Integer>> binaryTreePathSum(TreeNode root, int target) { 2 // Write your code here 3 List<List<Integer>> results = new ArrayList<List<Integer>>(); 4 if (root == null) { 5 return results; 6 } 7 help(results, new ArrayList<Integer>(), root, target); 8 return results; 9 } 10 public void help(List<List<Integer>> results, List<Integer> cur, 11 TreeNode root, int target) { 12 cur.add(root.val); 13 if (target == root.val && root.left == null && root.right == null) { 14 results.add(new ArrayList<Integer>(cur)); 15 } 16 if (root.left != null) { 17 help(results, cur, root.left, target - root.val); 18 } 19 if (root.right != null) { 20 help(results, cur, root.right, target - root.val); 21 } 22 cur.remove(cur.size() - 1); 23 }
扭转后等价的二叉树
检查两棵二叉树是否在经过若干次扭转后可以等价。扭转的定义是,交换任意节点的左右子树。等价的定义是,两棵二叉树必须为相同的结构,并且对应位置上的节点的值要相等。
1 public boolean isTweakedIdentical(TreeNode a, TreeNode b) { 2 // Write your code here 3 if (a == null && b == null) { 4 return true; 5 } 6 if (a == null || b == null || a.val != b.val) { 7 return false; 8 } 9 return isTweakedIdentical(a.left, b.left) 10 && isTweakedIdentical(a.right, b.right) 11 || 12 ( isTweakedIdentical(a.left, b.right) 13 && isTweakedIdentical(a.right, b.left)); 14 }
对称二叉树
1 public boolean isSymmetric(TreeNode root) { 2 // Write your code here 3 if (root == null) { 4 return true; 5 } 6 return help(root.left, root.right); 7 } 8 public boolean help(TreeNode left, TreeNode right) { 9 if(left == null && right == null) { 10 return true; 11 } 12 if (left == null || right == null || left.val != right.val) { 13 return false; 14 } 15 return help(left.left, right.right) 16 && help(left.right, right.left); 17 }
完全二叉树
只有最后一层可以不满,最后一层从左到右排列。所以可以使用层序遍历,遍历同层的时候看看是否有左边空了,右边不空的情况。遍历下一层的时候看看是否有上层不满的情况。
之前两种思路:第一种看是否所有节点的左子树节点数大于等于右子树节点数,这是不对的,例如:1 2 3 4 # 5
另外一种看叶子节点数目是不是所有节点数目的上限一半也是有问题的,例如: 1 2 3 # # 4
1 public boolean isComplete(TreeNode root) { 2 // Write your code here 3 Queue<TreeNode> queue = new LinkedList<>(); 4 if (root == null) { 5 return true; 6 } 7 queue.offer(root); 8 int num = 1; 9 while (!queue.isEmpty()) { 10 int size = queue.size(); 11 if (num != size && queue.peek().left!=null) { 12 return false; 13 } 14 num = num * 2; 15 boolean flag = true; 16 for (int i = 0; i < size; i++) { 17 TreeNode cur = queue.poll(); 18 if (!flag && (cur.left != null || cur.right != null)) { 19 return false; 20 } 21 if (cur.left != null) { 22 queue.offer(cur.left); 23 if (cur.right != null) { 24 queue.offer(cur.right); 25 } 26 else { 27 flag = false; 28 } 29 } 30 else { 31 if (cur.right != null) { 32 return false; 33 } 34 flag = false; 35 } 36 } 37 } 38 return true; 39 }
前序遍历和中序遍历树构造二叉树
1 public TreeNode buildTree(int[] preorder, int[] inorder) { 2 // write your code here 3 if (preorder == null || preorder.length == 0 4 || inorder == null || preorder.length != inorder.length) { 5 return null; 6 } 7 Map<Integer,Integer> map = new HashMap<Integer, Integer>(); 8 for (int i = 0; i < inorder.length; i++) { 9 map.put(inorder[i], i); 10 } 11 return buildHelp(preorder, 0, preorder.length - 1, 12 inorder, 0, inorder.length - 1, map); 13 } 14 public TreeNode buildHelp(int[] preorder, int pre_begin, int pre_end, 15 int[] inorder, int in_begin, int in_end, 16 Map<Integer,Integer> map) { 17 if (pre_begin > pre_end) { 18 return null; 19 } 20 if (pre_begin == pre_end) { 21 return new TreeNode(preorder[pre_begin]); 22 } 23 TreeNode root = new TreeNode(preorder[pre_begin]); 24 int index = map.get(preorder[pre_begin]); 25 root.left = buildHelp(preorder, pre_begin + 1, pre_begin + index - in_begin, 26 inorder, in_begin, index - 1, map); 27 root.right = buildHelp(preorder, pre_begin + index - in_begin + 1, pre_end, 28 inorder, index + 1, in_end, map); 29 return root; 30 }
中序遍历和后序遍历树构造二叉树
1 public TreeNode buildTree(int[] inorder, int[] postorder) { 2 // write your code here 3 if (inorder == null || inorder.length == 0 4 || postorder == null || postorder.length != inorder.length) { 5 return null; 6 } 7 Map<Integer,Integer> map = new HashMap<Integer,Integer>(); 8 for (int i = 0; i < inorder.length; i++) { 9 map.put(inorder[i],i); 10 } 11 return buildHelp(inorder, 0, inorder.length - 1, 12 postorder, 0, postorder.length - 1, map); 13 } 14 public TreeNode buildHelp(int[] inorder, int in_start, int in_end, 15 int[] postorder, int post_start, int post_end, 16 Map<Integer,Integer> map) { 17 if (in_start > in_end) { 18 return null; 19 } 20 if (in_start == in_end) { 21 return new TreeNode(postorder[post_end]); 22 } 23 TreeNode root = new TreeNode(postorder[post_end]); 24 int index = map.get(root.val); 25 root.left = buildHelp(inorder, in_start, index - 1, 26 postorder, post_start, post_start + index - 1 - in_start, 27 map); 28 root.right = buildHelp(inorder, index + 1, in_end, 29 postorder, post_start + index - in_start, post_end - 1, 30 map); 31 return root; 32 }
二叉查找树中搜索区间
给定两个值 k1 和 k2(k1 < k2)和一个二叉查找树的根节点。
找到树中所有值在 k1 到 k2 范围内的节点。
即打印所有x (k1 <= x <= k2) 其中 x 是二叉查找树的中的节点值。
返回所有升序的节点值。
1 public ArrayList<Integer> searchRange(TreeNode root, int k1, int k2) { 2 // write your code here 3 ArrayList<Integer> res = new ArrayList<Integer>(); 4 helper(root, k1, k2, res); 5 return res; 6 } 7 public void helper(TreeNode root, int k1, int k2, ArrayList<Integer> res) { 8 if (root == null) { 9 return ; 10 } 11 if (root.val > k1) { 12 helper(root.left, k1, k2, res); 13 } 14 if (root.val >= k1 && root.val <= k2) { 15 res.add(root.val); 16 } 17 if (root.val < k2) { 18 helper(root.right, k1, k2, res); 19 } 20 }
二叉树的序列化和反序列化
使用前序遍历比层序遍历来得简单直观的多。
1 public String serialize(TreeNode root) { 2 // write your code here 3 StringBuilder sb = new StringBuilder(); 4 bulidString(root, sb); 5 return sb.toString(); 6 } 7 public void bulidString(TreeNode root, StringBuilder sb) { 8 if (root == null) { 9 sb.append("#,"); 10 } 11 else { 12 sb.append(root.val).append(","); 13 bulidString(root.left, sb); 14 bulidString(root.right, sb); 15 } 16 } 17 public TreeNode deserialize(String data) { 18 // write your code here 19 Queue<String> queue = new LinkedList<String>(); 20 queue.addAll(Arrays.asList(data.split(","))); 21 return buildTree(queue); 22 } 23 public TreeNode buildTree(Queue<String> queue) { 24 String cur = queue.poll(); 25 if (cur.equals("#")) { 26 return null; 27 } 28 else { 29 TreeNode root = new TreeNode(Integer.valueOf(cur)); 30 root.left = buildTree(queue); 31 root.right = buildTree(queue); 32 return root; 33 } 34 }
删除二叉查找树的节点***
给定一棵具有不同节点值的二叉查找树,删除树中与给定值相同的节点。如果树中没有相同值的节点,就不做任何处理。你应该保证处理之后的树仍是二叉查找树。
eeNode parent = findNode(dummy, root, value);//值为value的节点的父节点
1 public TreeNode deleteNode(TreeNode root, int key) { 2 TreeNode dummy = new TreeNode(0); 3 dummy.left = root; 4 TreeNode parent = findNode(dummy, root, key); 5 TreeNode node = null; 6 if (parent.left != null && parent.left.val == key) { 7 node = parent.left; 8 } else if (parent.right != null && parent.right.val == key) { 9 node = parent.right; 10 } else { 11 return dummy.left; 12 } 13 deleteNode(parent, node); 14 return dummy.left; 15 16 } 17 public void deleteNode(TreeNode parent, TreeNode node) { 18 if (node.right == null) { 19 if (parent.left == node) { 20 parent.left = node.left; 21 return; 22 } else { 23 parent.right = node.left; 24 return; 25 } 26 } 27 TreeNode father = node; 28 TreeNode rightMin = node.right; 29 while (rightMin.left != null) { 30 father = rightMin; 31 rightMin = rightMin.left; 32 } 33 if (father.left == rightMin) { 34 father.left = rightMin.right; 35 } else { 36 father.right = rightMin.right; 37 } 38 if (parent.left == node) { 39 parent.left = rightMin; 40 } else { 41 parent.right = rightMin; 42 } 43 rightMin.left = node.left; 44 rightMin.right = node.right; 45 } 46 public TreeNode findNode(TreeNode parent, TreeNode root, int key) { 47 if (root == null) { 48 return parent; 49 } 50 if (root.val == key) { 51 return parent; 52 } 53 if (root.val < key) { 54 return findNode(root, root.right, key); 55 } else { 56 return findNode(root, root.left, key); 57 } 58 }
Kth Smallest Element in a BST
Given a binary search tree, write a function kthSmallest
to find the kth smallest element in it.
方法一:中序遍历之后直接取得
1 def kthSmallest(self, root, k): 2 """ 3 :type root: TreeNode 4 :type k: int 5 :rtype: int 6 """ 7 if not root: 8 return -1 9 res=[] 10 self.inorderTranverse(root, res) 11 return res[k - 1] 12 def inorderTranverse(self, root, res): 13 if root.left: 14 self.inorderTranverse(root.left, res) 15 res.append(root.val) 16 if root.right: 17 self.inorderTranverse(root.right, res)
方法二:中序遍历到第k个元素返回
1 def kthSmallest(self, root, k): 2 """ 3 :type root: TreeNode 4 :type k: int 5 :rtype: int 6 """ 7 if not root: 8 return -1 9 num = 0 10 stack = [] 11 while root or len(stack)!=0: 12 while root: 13 stack.append(root) 14 root = root.left 15 node = stack.pop() 16 num += 1 17 if num == k: 18 return node.val 19 if node.right: 20 root = node.right 21 return -1
方法三:二分查找
1 def kthSmallest(self, root, k): 2 """ 3 :type root: TreeNode 4 :type k: int 5 :rtype: int 6 """ 7 if not root: 8 return -1 9 leftNum = self.getNodeNum(root.left) 10 if leftNum >= k: 11 return self.kthSmallest(root.left,k) 12 elif leftNum < k - 1: 13 return self.kthSmallest(root.right, k - leftNum - 1) 14 else: 15 return root.val 16 def getNodeNum(self, root): 17 if not root: 18 return 0 19 else: 20 return self.getNodeNum(root.left) + self.getNodeNum(root.right) + 1
Binary Tree Serialization
1 public String serialize(TreeNode root) { 2 // write your code here 3 StringBuilder sb = new StringBuilder(); 4 return buildString(root, sb); 5 } 6 7 private String buildString(TreeNode root, StringBuilder sb) { 8 if (root == null) { 9 sb.append("#,"); 10 return sb.toString(); 11 } 12 sb.append(root.val + ","); 13 buildString(root.left, sb); 14 buildString(root.right, sb); 15 return sb.toString(); 16 } 17 public TreeNode deserialize(String data) { 18 // write your code here 19 if (data == null || data.length() == 0) { 20 return null; 21 } 22 String[] strs = data.split(","); 23 Queue<String> queue = new LinkedList<String>(); 24 queue.addAll(Arrays.asList(strs)); 25 return buildNode(queue); 26 } 27 28 private TreeNode buildNode(Queue<String> queue) { 29 String cur = queue.poll(); 30 if (cur.equals("#")) { 31 return null; 32 } else { 33 TreeNode root = new TreeNode(Integer.valueOf(cur)); 34 root.left = buildNode(queue); 35 root.right = buildNode(queue); 36 return root; 37 } 38 }