幾種常見的二叉樹:node
滿二叉樹 :除了葉子節點外,全部節點都有兩個兒子,深度爲 k 的滿二叉樹具備 2^k - 1 個節點。面試
徹底二叉樹 :若設二叉樹的高度爲h,除第h層外,其餘各層 (1 ~ h -1)層節點都達到最大個數,第h層的葉子節點從左到右依次排列。算法
平衡二叉樹(AVL) :是一棵平衡的二叉查找樹。任何一個節點的左右兩個兒子的高度差不超過1,而且其左右子樹都是平衡二叉樹。app
二叉查找樹(BST) : 左 < 根 < 右。(BST不必定是平衡二叉樹)ide
遇到二叉樹問題,就想一想整棵樹在該問題上的結果和左右子樹在該問題上的結果之間的聯繫。post
二叉樹問題經常伴隨着遍歷出現,基本的就有前序遍歷,中序遍歷,後續遍歷。三種遍歷的實現分爲遞歸實現和非遞歸實現,而遞歸實現又能夠分爲遍歷法和分治法。區分遍歷法能夠簡單想爲遍歷就是都是本身去作,而分治是分給本身的小弟去作。ui
通常分子二叉樹問題均可以使用分治,就是無腦的先丟給左子樹,而後無腦的丟給右子樹,獲得左右子樹的結果以後再考慮根節點。this
這裏就先給出三種遍歷的三種實現方法。前序遍歷:根左右 中序遍歷:左根右 後續遍歷:左右根spa
前序遍歷遍歷法:3d
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 }
給一棵二叉樹和二叉樹中的兩個節點,找到這兩個節點的最近公共祖先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 }
給一棵二叉樹和二叉樹中的兩個節點,找到這兩個節點的最近公共祖先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 }
給一棵二叉樹,找出從根節點出發的路徑中,和最大的一條。
這條路徑能夠在任何二叉樹中的節點結束,可是必須包含至少一個點(也就是根了)。
注意節點值可能爲負數。無腦分給左右兒子就行。
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 }
注意二叉查找樹不必定是平衡的,因此其查找複雜度不必定就是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 }
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
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 }