Posts Tagged ‘tree’
算法:
- arch代表穿过当前节点的路径(左边一支儿+自己节点+右边一支儿)。
- 注意树的节点可以是负数,所以arch不一定是最长的。
- 每次return以root(当前节点)开头最大的单只path sum。
- res[]就是一个存result的reference object,java不支持c++那种直接&传reference,
所以要么用个长度为一的数组,要么写个wrapper。还是用数组简单。 - update res[0],用arch和以自己开头一支儿的比,谁大就把res[0] update成谁。
public int maxPathSum(TreeNode root) { int[] res = new int[1]; res[0] = Integer.MIN_VALUE; maxPath(root, res); return res[0]; } private int maxPath(TreeNode root, int[] res) { if (root == null) return 0; int left = maxPath(root.left, res);//左边一支儿(不算自己) int right = maxPath(root.right, res); int arch = left + right + root.val; //穿过自己 int single = Math.max(root.val, Math.max(left, right) + root.val); //(算上自己) res[0] = Math.max(res[0], Math.max(arch, single));//update结果 return single; }
树的dfs变形,还是两个list来回倒。但是这题上来就写还不行,真心得在纸上画一画才能看出来规律。一开始觉得keep一个boolean,正常顺序就加后面,逆序就加前面呗,但是没注意到parent其实很可能已经不是原来顺序的了。画个四层的树就能看出来咋回事了。还有一个小bug就是最开始的boolean reverse应该是true,因为他代表了“parent下面一层要什么顺序”,而不是parent本身是什么顺序。所以还是,变量的物理意义一定要搞清再写!
public ArrayList<ArrayList<Integer>> zigzagLevelOrder(TreeNode root) {
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
if (root == null)
return result;
ArrayList<TreeNode> parents = new ArrayList<TreeNode>();
boolean reverse = true;//first children line is reversed
parents.add(root);
while (!parents.isEmpty()) {
ArrayList<TreeNode> children = new ArrayList<TreeNode>();
for (int i = parents.size() - 1; i >= 0; i--) {
TreeNode parent = parents.get(i);
if (!reverse) {// the children list wants to be normal order
if (parent.left != null)
children.add(parent.left);
if (parent.right != null)
children.add(parent.right);
} else { //the children wants to be right to left
if (parent.right != null)
children.add(parent.right);
if (parent.left != null)
children.add(parent.left);
}
}
result.add(convertToIntegerList(parents));
reverse = !reverse;
parents = children;
}
return result;
}
这个是left bound, right bound来check if a tree is a BST的变形。愣是没看出来。还是不熟练,桑心。挖坑,要是明天挂了回来接着写。
http://leetcode.com/2010/09/saving-binary-search-tree-to-file.html
[summery] Tree的解法总结
Posted October 11, 2013
on:- 中序遍历(BST),用一个TreeNode[1] reference wrapper keep顺序的上一个节点是谁
- 前序遍历(BST),用left bound right bound来判断/决定位置。
- In: classic | leetcode
- Leave a Comment
用两个stack O(n)的方法:
- 一个stack s1 push root。
- 一边pop s1进s2,一边把pop的left, right push进s1(先左后右,这先进s2的是右边,左边在s2靠前部分,所以最后先print出来)
- 这样最后s2就是一个正好从上到下是post order的traversal,一边pop一边print就行了。
public void postOrderTwoStacks(TreeNode root) { Stack<TreeNode> s1 = new Stack<TreeNode>(); Stack<TreeNode> s2 = new Stack<TreeNode>(); s1.push(root); while (!s1.isEmpty()) { TreeNode pop = s1.pop(); s2.push(pop); if (pop.left != null) s1.push(pop.left); if (pop.right != null) s1.push(pop.right); } while (!s2.isEmpty()) { System.out.print(s2.pop().val + ", "); } }
用一个stack O(h)的方法:
- 一个stack,先push root
- keep一个prev variable表示刚才试过的node(在stack里尝试来着,不管最后是否把它pop出去了),一直在更新。
- stack.peek() == curr,每次用curr和prev比较
- 如果prev是空或者prev是curr的parent,说明在top down的traverse,这时候可不能print prev(那就变成preorder了);而应该push curr的左子,木有才push右子,全都木有说明curr是leaf,就pop print就行了。
- 如果prev是curr的左子,说明在从左下角往上traverse,这时若curr有右子,则push右子(应该traverse右子)- prev应该是已经pop出来的了。
- 如果prev是curr的右子,说明从右下角往左上traverse,这时直接pop print curr就行了,因为这时root也该出来了。
public void postOrder(TreeNode root) { Stack<TreeNode> s = new Stack<TreeNode>(); s.push(root); TreeNode prev = null; while (!s.isEmpty()) { TreeNode curr = s.peek(); if (prev == null || prev.left == curr || prev.right == curr) { // top down if (curr.left != null) s.push(curr.left); else if (curr.right != null) s.push(curr.right); else {// is leaf popAndPrint(s, curr); } } else if (prev == curr.left) { // from left child to parent if (curr.right != null) s.push(curr.right); else { popAndPrint(s, curr); } } else { // prev.right == curr, from right child to parent popAndPrint(s, curr); } prev = curr; } }
private void popAndPrint(Stack<TreeNode> s, TreeNode curr) { System.out.print(curr.val + ", "); s.pop(); }
- In: classic | leetcode
- Leave a Comment
经典题,注意balanced的定义:左右子树都balance,且高度差<=1。所以下面这个也是balanced的,即使a的做右子树都不是完全树。
a / \ b d / \ c e
唯一的trick:不用生成新的data structure来保存“boolean isBalanced, int height”,直接用height = -1表示不平衡就行。
public boolean isBalanced(TreeNode root) { return getHeight(root) >= 0; } private int getHeight(TreeNode root) { if (root == null) return 0; int leftHeight = getHeight(root.left); if (leftHeight < 0) return -1; int rightHeight = getHeight(root.right); if (rightHeight < 0) return -1; if (Math.abs(leftHeight - rightHeight) > 1) return -1; return Math.max(leftHeight, rightHeight) + 1; }
这题看似很难,因为树的rotation完全不会;但是咬牙想了五分钟就bug free的写出来了,一遍过,看来树的recursive理解已经挺到位了。
算法:1~n中每个数字都可以是root,定了谁是root之后(比如k),他的左子树只能是1~k-1组成的,右子树只能是k+1~n组成的。左子树的variation数目×右子树的就是k作为root的有几种rotation。有点要注意:终止条件有两种:
- p == q,说明就一个节点了,没啥可转的,就一种return 1
- p > q,说明这一段已经不存在了,这时不应该return 0,因为这正是子树是null的情况!所以还应该return 1
public int numTrees(int n) { return getWays(1, n); } int getWays(int p, int q) { if (p >= q) return 1; int ways = 0; for (int i = p; i <= q; i++) { int leftWays = getWays(p, i - 1); int rightWays = getWays(i + 1, q); ways += leftWays * rightWays; } return ways; }
- In: 面经
- Leave a Comment
别用傻乎乎的additional data structure,那样可以做,但是写起来太长。这个题上来的思路就是用左中右的inorder,这样一路下来,prev.next = curr,不断update当前的node为prev。但是写了半天,不知道怎么传prev,因为担心传java reference的问题;又回到了那个IntWrapper tree serialization的题。都是一个类型:https://leetcodenotes.wordpress.com/2013/08/24/phone-serializede-serialize-a-tree/
public void addSuccessor(Node node, Node[] prev) { if (node == null) return; addSuccessor(node.left, prev); if (prev[0] != null) prev[0].next = node; prev[0] = node; addSuccessor(node.right, prev); }
类似题:找tree的in order traversal第x个节点:keep一个current node的index counter,同样是inorder的pattern,到当前node的时候counter++。这个init的i应该是-1,因为第一次找到最左边的节点的时候,i先+1,然后和x比较。
public TreeNode getNthNode(TreeNode node, IntWrapper i, int x) { if (node == null) return null; TreeNode foundAtLeft = getNthNode(node.left, i, x); i.val++; if (i.val == x) return node; if (foundAtLeft != null) return foundAtLeft; return getNthNode(node.right, i, x); }
- In: 面经
- Leave a Comment
对这类题型其实不够熟悉,写了有15分钟才出来,太差了。总结一下。
BST一般找不到就null了,没办法keep track of走到哪个位置的信息。所以多传两个参数,leftBoundary和rightBoundary,分别表示“当前node为root的子树的left boundary – 当前子树的immediate prev)“和“immediate next”。因为你是top down的往下算,所以左右两边的boundary不断narrow down。当node == null时,此时的最靠近自己的boundary就起作用了,找他们之间最接近x的就行了。
这题和判断一棵树是不是BST是一个套路(后面有对比):
public TreeNode getClosest(TreeNode node, TreeNode leftBoundary, TreeNode rightBoundary, int x) { if (node == null) return getClosest(leftBoundary, rightBoundary, x); if (node.val < x) { return getClosest(node.right, node, rightBoundary, x); } else { return getClosest(node.left, leftBoundary, node, x); } } private TreeNode getClosest(TreeNode prev, TreeNode next, int x) { if (prev == null || next == null) return prev == null ? next : prev; if (next.val - x < x - prev.val) return next; else return prev; }
附加:判断一棵树是不是BST,也是一路传下来boundary,不断看当前节点是不是满足上面传下来的左右boundary, 然后往下传的时候narrow down。最开始left, right, node都是null(没有左右节点限制)。
boolean isBST(Node node, Node leftBoundary, Node rightBoundary) { if (node == null) return true; if ((leftBoundary != null && node.val < leftBoundary.val) || (rightBoundary != null && node.val > rightBoundary.val)) return false; if (!isBST(node.left, leftBoundary, node)) return is BST(node.right, node, rightBoundary); }