Leetcode总结之Tree
Posted 我的名字叫周周
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode总结之Tree相关的知识,希望对你有一定的参考价值。
package Tree; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Deque; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.Stack; class ListNode { int val; ListNode next; ListNode(int x) { val = x; } } class TreeLinkNode { int val; TreeLinkNode left, right, next; TreeLinkNode(int x) { val = x; } } class TreeNode { public int val; public TreeNode left; public TreeNode right; public TreeNode(int x) { val = x; } } public class TreeProblems { public static void main(String[] args) { // TODO Auto-generated method stub TreeLinkNode a1 = new TreeLinkNode(1); TreeLinkNode a2 = new TreeLinkNode(2); TreeLinkNode a3 = new TreeLinkNode(3); TreeLinkNode a4 = new TreeLinkNode(4); TreeLinkNode a5 = new TreeLinkNode(5); TreeLinkNode a6 = new TreeLinkNode(6); TreeLinkNode a7 = new TreeLinkNode(7); a1.left = a2; a1.right = a3; a2.left = a4; a2.right = a5; a3.left = a6; a3.right = a7; System.out.println(a5.next.val); TreeNode aaa1 = new TreeNode(4); TreeNode aaa2 = new TreeNode(1); TreeNode aaa3 = new TreeNode(2); TreeNode aaa4 = new TreeNode(3); aaa1.left = aaa2; aaa2.left = aaa3; aaa3.left = aaa4; /* * 9 5 13 1 7 10 */ TreeNode aa1 = new TreeNode(5); TreeNode aa2 = new TreeNode(4); TreeNode aa3 = new TreeNode(8); TreeNode aa4 = new TreeNode(11); TreeNode aa5 = new TreeNode(13); TreeNode aa6 = new TreeNode(4); TreeNode aa7 = new TreeNode(7); TreeNode aa8 = new TreeNode(2); TreeNode aa9 = new TreeNode(1); aa1.left = aa2; aa1.right = aa3; aa2.left = aa4; aa3.left = aa5; aa3.right = aa6; aa4.left = aa7; aa4.right = aa8; aa6.right = aa9; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //树的问题很多都是dfs的问题,首先要学会preorder,inorder,postorder三种dfs算法的两种实现方式。 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * 94. Binary Tree Inorder Traversal * 2015.11.21 By Mingyang * 跟preorder一样的dfs,不过是每次pop出来的时候记在小本本上,也就是记在list里面 中序遍历迭代解法 * 用栈先把根节点的所有左孩子都添加到栈内, 然后输出栈顶元素,再处理栈顶元素的右子树 */ public List<Integer> inorderTraversal(TreeNode root) { List<Integer> list = new ArrayList<Integer>(); if (root == null) return list; Stack<TreeNode> stack = new Stack<TreeNode>(); TreeNode p = root; while (!stack.isEmpty() || p != null) { if (p != null) { stack.push(p); p = p.left; } else { TreeNode t = stack.pop(); list.add(t.val); p = t.right; } } return list; } public List<Integer> inorderTraversal1(TreeNode root) { List<Integer> res = new ArrayList<Integer>(); dfs(root, res); return res; } public void dfs(TreeNode root, List<Integer> res) { if (root == null) return; dfs(root.left, res); res.add(root.val); dfs(root.right, res); } /* * 144. Binary Tree Preorder Traversal * 2015.11.21 By Mingyang * 典型的dfs的做法,每次push进去一个值的时候就记在小本本上,其实也就是记在list里面 */ public List<Integer> preorderTraversal(TreeNode root) { List<Integer> list = new ArrayList<Integer>(); if (root == null) return list; Stack<TreeNode> stack = new Stack<TreeNode>(); TreeNode p = root; while (!stack.isEmpty() || p != null) { if (p != null) { stack.push(p); list.add(p.val); p = p.left; } else { TreeNode t = stack.pop(); p = t.right; } } return list; } public List<Integer> preorderTraversal1(TreeNode root) { List<Integer> res=new ArrayList<Integer>(); dfs(res,root); return res; } public void dfs(List<Integer> res,TreeNode root){ if(root==null) return; res.add(root.val); dfs(res,root.left); dfs(res,root.right); } /* * 145. Binary Tree Postorder Traversal * 2015.11.21 by Mingyang * 左右中,反过来就是中左右,所以就相当于inorder反过来,稍稍改进一下就好 */ public List<Integer> postorderTraversal(TreeNode root) { List<Integer> list = new ArrayList<Integer>(); if (root == null) return list; Stack<TreeNode> stack = new Stack<TreeNode>(); TreeNode p = root; while (!stack.isEmpty() || p != null) { if (p != null) { stack.push(p); list.add(p.val); p = p.right; } else { TreeNode t = stack.pop(); p = t.left; } } Collections.reverse(list); return list; } public List<Integer> postorderTraversal1(TreeNode root) { List<Integer> res=new ArrayList<Integer>(); dfs(root,res); return res; } public void dfs1(TreeNode root,List<Integer> res){ if(root==null) return; dfs1(root.left,res); dfs1(root.right,res); res.add(root.val); } /* * 95. Unique Binary Search Trees II * 2015.11.23 By Mingyang * 分成两个函数来写,另外一个函数写满起点到终点 */ public List<TreeNode> generateTrees(int n) { return generateTrees(1, n); } public List<TreeNode> generateTrees(int start, int end) { List<TreeNode> list = new LinkedList<TreeNode>(); if (start > end) { list.add(null); return list; } for (int i = start; i <= end; i++) { List<TreeNode> lefts = generateTrees(start, i - 1);//以i作为根节点,左子树由[1,i-1]构成 List<TreeNode> rights = generateTrees(i + 1, end);//右子树由[i+1, n]构成 for (TreeNode left : lefts) {//左边和右边分别返回了一个list,每个值就是一个TreeNode,就代表一种可能性 for (TreeNode right : rights) { TreeNode node = new TreeNode(i); node.left = left; node.right = right; list.add(node);//存储所有可能行 } } } return list; } /* * 145. Binary Tree Postorder Traversal * 上面的变体,给你一个preorder的array,看看是不是BST的preorder * 2015.1.24 by Mingyang */ public static boolean canRepresentBST(int pre[], int n) { // Create an empty stack Stack<Integer> s = new Stack<Integer>(); // Initialize current root as minimum possible // value int root = Integer.MIN_VALUE; // Traverse given array for (int i = 0; i < n; i++) { // If we find a node who is on right side // and smaller than root, return false if (pre[i] < root) { return false; } // If pre[i] is in right subtree of stack top, // Keep removing items smaller than pre[i] // and make the last removed item as new // root. while (!s.empty() && s.peek() < pre[i]) { root = s.peek(); s.pop(); } // At this point either stack is empty or // pre[i] is smaller than root, push pre[i] s.push(pre[i]); } return true; } /* * 156.Binary Tree Upside Down * 2016-3-26 by Mingyang * For example: *Given a binary tree {1,2,3,4,5}, 1 / 2 3 / 4 5 *return the root of the binary tree [4,5,2,#,#,3,1]. 4 / 5 2 / 3 1 *先去处理最左下角的分支,因为他就是未来的root,然后再一层一层的上来 */ public TreeNode UpsideDownBinaryTree(TreeNode root) { if (root == null) return null; TreeNode parent = root, left = root.left, right = root.right; if (left != null) { TreeNode ret = UpsideDownBinaryTree(left); left.left = right; left.right = parent; return ret; } return root; } /* * 272.Closest Binary Search Tree Value II * 2016-3-27 By Mingyang * 二叉搜索树的中序遍历就是顺序输出二叉搜索树,所以我们只要中序遍历二叉搜索树,同时维护一个大小为K的队列, * 前K个数直接加入队列,之后每来一个新的数(较大的数),如果该数和目标的差,相比于队头的数离目标的差来说, * 更小,则将队头拿出来,将新数加入队列。如果该数的差更大,则直接退出并返回这个队列,因为后面的数更大,差值也只会更大。 * @return true if result is already found. */ public List<Integer> closestKValues(TreeNode root, double target, int k) { LinkedList<Integer> list = new LinkedList<Integer>(); closestKValuesHelper(list, root, target, k); return list; } private boolean closestKValuesHelper(LinkedList<Integer> list,TreeNode root, double target, int k) { if (root == null) { return false; } if (closestKValuesHelper(list, root.left, target, k)) { return true; } if (list.size() == k) { if (Math.abs(list.getFirst() - target) < Math.abs(root.val - target)) { return true; } else { list.removeFirst(); } } list.addLast(root.val); return closestKValuesHelper(list, root.right, target, k); } /* * 270 Closest Binary Search Tree Value * Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target. * 2016-3-26 by Mingyang * 其实很简单,就是在dfs的过程中不断的缩小范围,没到一个点就开始去update最小的距离 */ public int closestValue3(TreeNode root, double target) { int closest = root.val; while (root != null) { // 如果该节点的离目标更近,则更新到目前为止的最近值 closest = Math.abs(closest - target) < Math.abs(root.val - target) ? closest: root.val; // 二叉搜索 root = target < root.val ? root.left : root.right; } return closest; } /* * 265.Count Univalue Subtrees * 2016-3-26 by Mingyang * Given a binary tree, count the number of uni-value subtrees. * A Uni-value subtree means all nodes of the subtree have the same value. * 这里是自底向上的模式, */ private int count = 0; public int countUnivalSubtrees(TreeNode root) { unival(root); return count; } private boolean unival(TreeNode root) { if (root == null) return true; if (root.left == null && root.right == null) { count++; return true; } boolean left = unival(root.left);//自底向上第一步,走到最底的那一层 boolean right = unival(root.right); if (left && right && (root.left == null || root.left.val == root.val)&& (root.right == null || root.right.val == root.val)) { count++; return true; } return false; } /* * 285.Inorder Successor in BST * 11.21 By Mingyang * Case1: Node has right subtree: Go deep to leftmost node in right subtree or find min in right subtree * Case2:No right subtree:1.go back to parent from left, parent is successor,and parent is unvisited * 2.from right, parent already visited, we need on more further * ---Go to the nearest ancestor for which given node would be in left subtree */ public TreeNode inorderSuccessor(TreeNode root, TreeNode p) { Stack<TreeNode> stk = new Stack<TreeNode>(); TreeNode curr = root; // 找到目标节点并把路径上的节点压入栈,也就是首先找到这个节点,大概时间是logn while(curr != p){ stk.push(curr); if(curr.val > p.val){ curr = curr.left; } else { curr = curr.right; } } // 如果目标节点有右节点,则找到其右节点的最左边的节点,就是下一个数 if(curr.right != null){ curr = curr.right; while(curr.left != null){ curr = curr.left; } return curr; } else { // 如果没有右节点,pop栈找到第一个比目标节点大的节点。因为如果目标没有右节点,那么就看他从左边还是右边回到父亲,如果从左边回到父亲,父亲就是下一个 //如果不是,go to the nearest ancestor for which given node would be in left subtree while(!stk.isEmpty() && stk.peek().val < curr.val){ stk.pop(); } // 如果栈都pop空了还没有比目标节点大的,说明没有更大的了 return stk.isEmpty() ? null : stk.pop(); } } /* * 255.Verify Preorder Sequence in Binary Search Tree * Given an array of numbers, * verify whether it is the correct preorder traversal sequence of a binary * search tree. * 11.21 By Mingyang * Time complexity O(n^2), space complexity O(1). */ public boolean verifyPreorder(int[] preorder) { if (preorder == null || preorder.length <= 1) { return true; } return dfs(preorder, 0, preorder.length - 1); } private boolean dfs(int[] preorder, int low, int hi) { if (low >= hi) { return true; } int root = preorder[low]; int i = low + 1; while (i <= hi && preorder[i] < root) { i++; } int j = i; while (j <= hi && preorder[j] > root) { j++; } if (j <= hi) { return false; } return dfs(preorder, low + 1, i - 1) && dfs(preorder, i, hi); } /* * 103. Binary Tree Zigzag Level Order Traversal * 11.21 By Mingyang */ public static ArrayList<ArrayList<Integer>> zigzagLevelOrder2(TreeNode root) { ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>(); if (root == null) return res; LinkedList<TreeNode> queue = new LinkedList<TreeNode>(); queue.add(root); int num = 0; boolean reverse = false;// a flag while (!queue.isEmpty()) { num = queue.size(); ArrayList<Integer> levelres = new ArrayList<Integer>(); for (int i = 0; i < num; i++) { TreeNode node = queue.poll(); levelres.add(node.val); if (node.left != null) queue.add(node.left); if (node.right != null) queue.add(node.right); } if (reverse) { Collections.reverse(levelres); reverse = false; } else { reverse = true; } res.add(levelres); } return res; } /* * 107. Binary Tree Level Order Traversal II 11.21 By Mingyang I的解答加一行: * Collections.reverse(results);就好了 */ /* * 102. Binary Tree Level Order Traversal * 11.21 by Mingyang 最基本的queue的做法 */ public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> results = new ArrayList<List<Integer>>(); ArrayList<Integer> result = new ArrayList<Integer>(); if (root == null) return results; LinkedList<TreeNode> queue = new LinkedList<TreeNode>(); queue.add(root); int currentNumber = 1; int nextNumber = 0; while (queue.size() != 0) { TreeNode temp = queue.poll(); result.add(temp.val); currentNumber--; if (temp.left != null) { queue.add(temp.left); nextNumber++; } if (temp.right != null) { queue.add(temp.right); nextNumber++; } if (currentNumber == 0) { results.add(result); currentNumber = nextNumber; nextNumber = 0; result = new ArrayList<Integer>(); } } return results; } /* * 222.Count Complete Tree Nodes * 11.20 By Mingyang * 最先各自计算最左边那一束到底的长度,再计算右边到底的长度,如果相等,ok,# of nodes = 2^h -1(计算满树很简单的!) * 若不相等,再继续迭代,这样做节省了很多时间 * T(n)=logn+2T(n/2),最后算出来就是n,其实可以这么理解,每个节点都只是访问了一次,所以还是n。注意树的高度是logn */ public int countNodes(TreeNode root) { if (root == null) return 0; int leftHeight = 1, rightHeight = 1; // 计算左子树 TreeNode temp = root.left; while (temp != null) { temp = temp.left; leftHeight++; } // 计算右子树 temp = root.right; while (temp != null) { temp = temp.right; rightHeight++; } if (leftHeight == rightHeight) return (1 << leftHeight) - 1; // 也可以:(2<<(left-1))-1,这里h是left-1 return countNodes(root.left) + countNodes(root.right) + 1; } /* * 226. Invert Binary Tree * 11.19 By Mingyang */ public TreeNode invertTree(TreeNode root){ exchange(root); return root; } public void exchange(TreeNode root) { if(root==null) return; if(root.left==null&&root.right==null) return; TreeNode Temp=root.left; root.left=root.right; root.right=Temp; exchange(root.left); exchange(root.right); } /* * 230.Kth Smallest Element in a BST * 11.19 By Mingyang */ private static int number = 0; private static int county = 0; public int kthSmallest1(TreeNode root, int k) { county = k; dfs(root); return number; } public void dfs(TreeNode root) { if (root == null) return; dfs(root.left); county--; if (county == 0) { number = root.val; return; } dfs(root.right); } public int kthSmallest(TreeNode root, int k) { Stack<TreeNode> stack = new Stack<TreeNode>(); TreeNode p = root; int result = 0; // 不断的dfs,利用左中右的遍历方式进行遍历,然后依次取到最后的值 while (!stack.isEmpty() || p != null) { if (p != null) { stack.push(p); p = p.left; } else { TreeNode t = stack.pop(); k--; if (k == 0) result = t.val; p = t.right; } } return result; } // 我的方法更快,利用左子树和右字数的个数的关系,如果k大于左子树的个数,那么就可以往右边走,这种方法复杂度T(n)=2T(n/2)+logn,也就是n //这里用了Binary Search的方法,根据count的大小来判断在哪个区间,然后去那个区间search,所以按理来说应该是logn,可是因为count用了n,所以总的时间就是n,哈哈! public int kthSmallest2(TreeNode root, int k) { int count = countNodes2(root.left); if (k <= count) { return kthSmallest2(root.left, k); } else if (k > count + 1) { return kthSmallest2(root.right, k-1-count); // 1 is counted as current node } return root.val; } public int countNodes2(TreeNode n) { if (n == null) return 0; return 1 + countNodes2(n.left) + countNodes2(n.right); } /* * 235. Lowest Common Ancestor of a Binary Search Tree * 11.19 By Mingyang * 这题目更简单,下面两种方法都适用,现在给出更直接的方法 */ public TreeNode lowestCommonAncestor3(TreeNode root, TreeNode p, TreeNode q) { if (p.val == root.val || q.val == root.val) return root; if ((p.val < root.val && q.val > root.val)|| (p.val > root.val && q.val < root.val)) return root; if (p.val < root.val) { return lowestCommonAncestor(root.left, p, q); } else { return lowestCommonAncestor(root.right, p, q); } } /* * 236. Lowest Common Ancestor of a Binary Tree * 11.19 By Mingyang * 这道题目比BST更难,不过这道题目的答案可以通用的 */ public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { // 发现目标节点则通过返回值标记该子树发现了某个目标结点 if (root == null || root == p || root == q) return root; // 查看左子树中是否有目标结点,没有为null TreeNode left = lowestCommonAncestor(root.left, p, q); // 查看右子树是否有目标节点,没有为null TreeNode right = lowestCommonAncestor(root.right, p, q); // 都不为空,说明做右子树都有目标结点,则公共祖先就是本身 if (left != null && right != null) return root; // 如果发现了目标节点,则继续向上标记为该目标节点 return left == null ? right : left; } /* * 298 Binary Tree Longest Consecutive Sequence * 2016-3-27 by Mingyang * The path refers to any sequence of nodes from some starting node to any node in the tree along the parent-child connections. * The longest consecutive path need to be from parent to child (cannot be the reverse). */ private int result = Integer.MIN_VALUE; public int longestConsecutive(TreeNode root) { if(root == null) return 0; dfs(root, 0, root); return result; } private void dfs(TreeNode root, int cur, TreeNode pre) { if(root == null) return; if(root.val == pre.val+1) cur++; else cur = 1; result = Math.max(result, cur); dfs(root.left, cur, root); dfs(root.right, cur, root); } /* * 333.Largest BST Subtree * 2016-3-27 by Mingyang * Given a binary tree, find the largest subtree which is a Binary Search Tree (BST) * where largest means subtree with largest number of nodes in it. * why not traverse up the tree using a bottom-up approach? * In other words, we verify the deeper nodes before we verify if the above nodes satisfy the BST requirements. * Using a bottom-up approach, we need to pass some information up the tree. * Obviously, we need to pass minimum and maximum values of the subtree as we traverse up the tree, so the above subtrees could be verified for BST’s properties * 自底向上的方法,不过需要存lower,upper的值以及size的大小 */ class Result { // (size, rangeLower, rangeUpper) -- size of current tree, range of current tree [rangeLower, rangeUpper] int size; int lower; int upper; Result(int size, int lower, int upper) { this.size = size; this.lower = lower; this.upper = upper; } } int max = 0; public int largestBSTSubtree(TreeNode root) { if (root == null) { return 0; } traverse(root, null); return max; } private Result traverse(TreeNode root, TreeNode parent) { if (root == null) { return new Result(0, parent.val, parent.val); } Result left = traverse(root.left, root); Result right = traverse(root.right, root); if (left.size==-1 || right.size==-1 || root.val<left.upper || root.val>right.lower) { return new Result(-1, 0, 0); } int size = left.size + 1 + right.size; max = Math.max(size, max); return new Result(size, left.lower, right.upper);//更新新的BST的范围,新的Size } } /* * 297. Serialize and Deserialize Binary Tree * 2016-3-27 by Mingyang */ class Codec { private static final String spliter = ","; private static final String NN = "X"; // Encodes a tree to a single string. public String serialize(TreeNode root) { StringBuilder sb = new StringBuilder(); buildString(root, sb); return sb.toString(); } private void buildString(TreeNode node, StringBuilder sb) { if (node == null) { sb.append(NN).append(spliter); } else { sb.append(node.val).append(spliter); buildString(node.left, sb); buildString(node.right,sb); } } // Decodes your encoded data to tree. public TreeNode deserialize(String data) { Deque<String> nodes = new LinkedList<String>(); nodes.addAll(Arrays.asList(data.split(spliter))); return buildTree(nodes); } private TreeNode buildTree(Deque<String> nodes) { String val = nodes.remove(); if (val.equals(NN)) return null; else { TreeNode node = new TreeNode(Integer.valueOf(val)); node.left = buildTree(nodes); node.right = buildTree(nodes); return node; } } }
以上是关于Leetcode总结之Tree的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode之104. Maximum Depth of Binary Tree
LeetCode题解之Diameter of Binary Tree
LeetCode题解之 Subtree of Another Tree