LintCode二叉树&递归分治题总结
来源:互联网 发布:淘宝妹子爱吃的零食 编辑:程序博客网 时间:2024/06/05 11:29
先来几个推荐的参考博客链接:
漫谈递归——递归的思想
非递归遍历二叉树总结
二叉树题总结
LintCode中二叉树与分治法那章有这么些题目:
376. Binary Tree Path Sum
要求等于target从根节点到叶子节点的路径和的组合,用DFS。
递归需要注意的是,终止情况是什么,也就是遇到叶子节点的时候返回,如果遇到叶子节点的时候恰好满足路径和等于target,就把这条路径加到总结果里面。
然后就是递归的主题,遇到左子节点、遇到右子节点的时候进入子递归。然后记得加入path路径后要remove掉,以方便保持当前路径的唯一性。
public List<List<Integer>> binaryTreePathSum(TreeNode root, int target) { List<List<Integer>> res = new ArrayList(); if (root == null) { return res; } ArrayList<Integer> path = new ArrayList<Integer>(); path.add(root.val); dfs(res, path, root, target, root.val); return res; } private void dfs(List<List<Integer>> res, ArrayList<Integer> path, TreeNode root, int target, int sum) { // 遇到叶子节点的返回条件 if (root.left == null && root.right == null) { if (sum == target) { res.add(new ArrayList<Integer>(path)); } return; } if (root.left != null) { path.add(root.left.val); dfs(res, path, root.left, target, sum + root.left.val); path.remove(path.size() - 1); } if (root.right != null) { path.add(root.right.val); dfs(res, path, root.right, target, sum + root.right.val); path.remove(path.size() - 1); } }
469. Identical Binary Tree
判断两个二叉树是否是完全一样的,连结构也要一样。很明显考的是递归。既然是递归,就注意终结条件,
自然是对不同情况的判断,参数就2个,2个树的root。
1)2个root皆空,则是identical的
2)2个root只有一个空,则非identical
3)2个root皆不空,并且root值不等,则非identical
4)2个root皆不空,并且root值相等,则进行子递归判断左子树和右子树
public boolean isIdentical(TreeNode a, TreeNode b) { if (a == null && b == null) { return true; } if (a == null || b == null) { return false; } if (a.val != b.val) { return false; } return isIdentical(a.left, b.left) && isIdentical(a.right, b.right); }
470. Tweaked Identical Binary Tree
也是判断2个二叉树是否完全一样,但是与上道题不同之处在于允许了对称扭曲。同样也是分4种情况判断:
public boolean isTweakedIdentical(TreeNode a, TreeNode b) { if (a == null && b == null) { return true; } if (a == null || b == null) { return false; } if (a.val == b.val) { return (isTweakedIdentical(a.left, b.right) && isTweakedIdentical(b.left, a.right)) || (isTweakedIdentical(a.left, b.left) && isTweakedIdentical(b.right, a.right)); } return false; }
468. Symmetric Binary Tree
判断一颗二叉树是不是对称的,跟上道题很像,只要把这颗树的左右子节点作为参数传进去就好。
public boolean isSymmetric(TreeNode root) { if (root == null) { return true; } if (root.left == null && root.right == null) { return true; } return helper(root.left, root.right); } public boolean helper(TreeNode a, TreeNode b) { if (a == null && b == null) { return true; } if (a == null || b == null) { return false; } if (a.val == b.val) { return (helper(a.left, b.right) && helper(b.left, a.right)); } return false; }
467. Complete Binary Tree
判断一棵树是不是完全二叉树。一个思路就是层次遍历,把每层的节点从左向右依此加入Stack,然后把Stack上层的None弹出,最后检查如果Stack中还有None说明不是Complete Tree 比如上面的不完全二叉树生成的数组为[1, 2, 3, None, 4, None, None],将右侧None弹出后为[1, 2, 3, None, 4],循环查找,发现还有None存在,所以是不完全二叉
public boolean isComplete(TreeNode root) { if (root == null) { return true; } Queue<TreeNode> q = new LinkedList<TreeNode>(); q.offer(root); boolean isNull = false; while (!q.isEmpty()) { TreeNode node = q.poll(); if (node.left != null) { if (isNull == true) { return false; } q.offer(node.left); } else { isNull = true; } if (node.right != null) { if (isNull == true) { return false; } q.offer(node.right); } else { isNull = true; } } return true; }
还有另外一种方法是递归,比较难理解,可以参考这篇博文:http://www.geeksforgeeks.org/check-whether-binary-tree-complete-not-set-2-recursive-solution/
或者参考这篇博客:http://stackoverflow.com/questions/1442674/how-to-determine-whether-a-binary-tree-is-complete
97. Maximum Depth of Binary Tree
求一个二叉树的最大深度。
public int maxDepth(TreeNode root) { if (root == null) { return 0; } return 1 + Math.max(maxDepth(root.left), maxDepth(root.right)); }
155. Minimum Depth of Binary Tree
求二叉树的最小深度,最小深度,就是从根节点到叶子节点最近的一条路的长度。不递归的话,可以用BFS层级遍历来做。
public int minDepth(TreeNode root) { if (root == null) { return 0; } Queue<TreeNode> q = new LinkedList<TreeNode>(); q.offer(root); int depth = 0; while (!q.isEmpty()) { int length = q.size(); depth++; for (int i = 0; i < length; i++) { TreeNode n = q.poll(); if (n.left == null && n.right == null) { return depth; } if (n.left != null) { q.offer(n.left); } if (n.right != null) { q.offer(n.right); } } } return depth; }也可以用递归来做,当当前节点是叶子节点时就返回结果。
public int minDepth(TreeNode root) { if (root == null) { return 0; } if (root.left == null && root.right == null) { return 1; } int l = (root.left == null) ? Integer.MAX_VALUE : minDepth(root.left); int r = (root.right == null) ? Integer.MAX_VALUE : minDepth(root.right); return 1 + Math.min(l, r); }
93. Balanced Binary Tree
判断一棵树是否为平衡二叉树。如果左右子树的最大高度差超过1的话,那就不是平衡的了。所以这道题是基于求树的最大高度的。
一开始可能会以为直接对左子树和右子树求高度,然后比较两树的高度差。这样的想法是错误的,比如下面这个树就不是平衡的。
所以在递归的过程中,对每一个节点进行高度平衡判断。只要中途有不平衡,那就是不平衡。如果左子树不平衡,那就是不平衡;如果右子树不平衡,那也是不平衡。
private int depth(TreeNode root) { if (root == null) { return 0; } int l = depth(root.left); int r = depth(root.right); if (Math.abs(l-r) > 1 || l == -1 || r == -1) { return -1; } return 1 + Math.max(l, r); } public boolean isBalanced(TreeNode root) { return depth(root) != -1; }
88. Lowest Common Ancestor
求最近公共父节点。参数是1个root节点和2个输入节点A、B。求得就是A和B的最近公共父节点。
查找两个node的最早的公共祖先,分三种情况:
1. 如果两个node在root的两边,那么最早的公共祖先就是root。
2. 如果两个node在root的左边,那么把root.left作为root,再递归。
3. 如果两个node在root的右边,那么把root.right作为root,再递归。
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) { if (root == null || root == A || root == B) { return root; } // divide TreeNode l = lowestCommonAncestor(root.left, A, B); TreeNode r = lowestCommonAncestor(root.right, A, B); // conquer if (l != null && r != null) { return root; } if (l != null) { return l; } if (r != null) { return r; } return null; }
474. Lowest Common Ancestor II
跟上道题类似,不过节点之间的关系是parent node的关系了。
如果每个结点都有一个指针指向它的父结点,于是我们可以从任何一个结点出发,得到一个到达树根结点的单向链表。因此这个问题转换为两个单向链表的第一个公共结点。
public ParentTreeNode lowestCommonAncestorII(ParentTreeNode root, ParentTreeNode A, ParentTreeNode B) { Stack<ParentTreeNode> s1 = new Stack(); Stack<ParentTreeNode> s2 = new Stack(); s1.push(A); s2.push(B); while (s1.peek().parent != null) { s1.push(s1.peek().parent); } while (s2.peek().parent != null) { s2.push(s2.peek().parent); } if (s1.empty() || s2.empty()) { return root; } ParentTreeNode res = null; while (!s1.empty() && !s2.empty() && s1.peek() == s2.peek()) { res = s1.pop(); s2.pop(); } return res; }
85. Insert Node in a Binary Search Tree
如果是用非递归的方法,则用一个while循环,找到那个需要插入的地方的父节点。
public TreeNode insertNode(TreeNode root, TreeNode node) { if (root == null) { return node; } TreeNode res = root; TreeNode father = null; while (root != null) { father = root; if (node.val > root.val) { root = root.right; } else { root = root.left; } } if (node.val > father.val) { father.right = node; } else { father.left = node; } return res; }如果是用递归的话,那看起来就比较简单了:
public TreeNode insertNode(TreeNode root, TreeNode node) { if (root == null) { return node; } if (node.val > root.val) { root.right = insertNode(root.right, node); } else { root.left = insertNode(root.left, node); } return root; }
87. Remove Node in Binary Search Tree
难度为Hard,Acceptance为25%.
首先,该题在《算法导论》一书中是有的。思路也较为容易理解,关键是实现算法时需要注意的各种细节。
那么下面说明该题的思路:
第一步,当然是找到要删除的节点node和它的父节点parent,这里采用普通的二分查找方法,找到了就返回node的父节点parent,找不到就返回null
第二步,就是删除该node节点,按照算法导论上的那个算法,删除node节点分为3种情况,1)node没有左右儿子,那么就直接把node的父节点指向node的儿子,即指向null。2)node只有一个儿子(左儿子或者右儿子),这个时候就直接把node的父节点指向左右儿子。3)node有2个儿子,那么这个时候就从左子树里面找到最小的那个节点,来代替node节点。
为了代码简洁,上述的3种情况可以简化为2种情况:
node没有左右儿子、node只有左儿子,可以合并为一种情况:即node的右子树不存在。此时,直接用parent节点的子节点指向该node节点的左节点。
node只有右儿子、node有左右2各儿子,可以合并为一种情况:即node的右子树存在。此时,需要找到node的右子树里的最小节点,用该节点替换node节点。
技巧:因为要删除的节点可能是根节点,因此为了算法的通用性,可以首先new一个dummy节点,该节点的左节点指向根节点,这样处理起来更为方便。
public TreeNode removeNode(TreeNode root, int key) { TreeNode dummy = new TreeNode(0); dummy.left = root; TreeNode parent = find(dummy, root, key); TreeNode node = null; // node 不存在 if (parent == null) { return root; } // node 在左边 if (parent.left != null && parent.left.val == key) { node = parent.left; } // node 在右边 if (parent.right != null && parent.right.val == key) { node = parent.right; } deleteNode(parent, node); return dummy.left; } private TreeNode find(TreeNode parent, TreeNode node, int key) { if(node == null) { return null; } if (key == node.val) { return parent; } if (key > node.val) { return find(node, node.right, key); } else { return find(node, node.left, key); } } private void deleteNode(TreeNode parent, TreeNode node) { // node的右子树不存在, 处理了两种情况,即只有左子树或者没有子树 if (node.right == null) { if (parent.right == node) { parent.right = node.left; } else { parent.left = node.left; } } else { // node的右子树存在, 且左子树不存在 if (node.left == null) { if (parent.right == node) { parent.right = node.right; } else { parent.left = node.right; } } else { // node的左右子树都存在,则寻找node右子树的最小节点,用于取代node TreeNode father = node; TreeNode t = node.right; while (t.left != null) { father = t; t = t.left; } if (father.left == t) { father.left = t.right; } else { father.right = t.right; } node.val = t.val; } } }
11. Search Range in Binary Search Tree
给定一个区间,要求在一个二叉查找树中,找到所有处在这个区间中的节点。最简单的思路就是先用dfs遍历,遍历过程中发现符合条件就加入ArrayList中。最后再对数组排序,返回。但是其实细细一想,是否可以免去这个排序的过程呢?是否可以在遍历的时候就能保持有序呢?考虑到二叉查找树的性质,如果用中序遍历,是可以保证这个的。
public void dfs(TreeNode root, ArrayList<Integer> res, int k1, int k2) { if (root != null) { dfs(root.left, res, k1, k2); if (root.val >= k1 && root.val <= k2) { res.add(root.val); } dfs(root.right, res, k1, k2); } } public ArrayList<Integer> searchRange(TreeNode root, int k1, int k2) { ArrayList<Integer> res = new ArrayList(); dfs(root, res, k1, k2); return res; }
66. Binary Tree Preorder Traversal
67. Binary Tree Inorder Traversal
68. Binary Tree Postorder Traversal
二叉树的前中后序遍历,递归的非常简单,就不再赘述了,非递归的可以参考这篇博客:http://zisong.me/post/suan-fa/geng-jian-dan-de-bian-li-er-cha-shu-de-fang-fa
69. Binary Tree Level Order Traversal
二叉树层次遍历,这个算法已经烂大街了,就不多说了
public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) { ArrayList<ArrayList<Integer>> res = new ArrayList(); if (root == null) { return res; } Queue<TreeNode> queue = new LinkedList<TreeNode>(); queue.offer(root); while(!queue.isEmpty()) { ArrayList<Integer> level = new ArrayList(); int size = queue.size(); for (int i = 0; i < size; i++) { TreeNode tmp = queue.poll(); level.add(tmp.val); if (tmp.left != null) { queue.offer(tmp.left); } if (tmp.right != null) { queue.offer(tmp.right); } } res.add(level); } return res; }
70. Binary Tree Level Order Traversal II
也是二叉树的层次遍历,不过是从叶子节点到根节点了,跟上道题类似,把最后的数组reverse一下就得到了。
就在上面的代码的最后加上这么一句就行:
Collections.reverse(res);
71. Binary Tree Zigzag Level Order Traversal
“之”字型的层次遍历,加个变量判断一下奇偶数就好。
public ArrayList<ArrayList<Integer>> zigzagLevelOrder(TreeNode root) { ArrayList<ArrayList<Integer>> res = new ArrayList(); if (root == null) { return res; } Queue<TreeNode> queue = new LinkedList<TreeNode>(); queue.offer(root); int level = 1; while(!queue.isEmpty()) { ArrayList<Integer> path = new ArrayList(); int size = queue.size(); level++; for (int i = 0; i < size; i++) { TreeNode tmp = queue.poll(); path.add(tmp.val); if (tmp.left != null) { queue.offer(tmp.left); } if (tmp.right != null) { queue.offer(tmp.right); } } if (level % 2 == 1) { Collections.reverse(path); } res.add(path); } return res; }
72. Construct Binary Tree from Inorder and Postorder Traversal
根据中序遍历和后续遍历结果,构建出那颗二叉树。要知道如何构建二叉树,首先我们需要知道二叉树的几种遍历方式,譬如有如下的二叉树:
1 --------|------- 2 3 ----|---- ----|---- 4 5 6 7
前序遍历 1245367
中序遍历 4251637
后续遍历 4526731
仍然以上面那棵二叉树为例,我们可以发现,对于后序遍历来说,最后一个元素一定是根节点,也就是1。然后我们在中序遍历的结果里面找到1所在的位置,那么它的左半部分就是其左子树,有半部分就是其右子树。
我们将中序遍历左半部分425取出,同时发现后序遍历的结果也在相应的位置上面,只是顺序稍微不一样,也就是452。我们可以发现,后序遍历中的2就是该子树的根节点。
上面说到了左子树,对于右子树,我们取出637,同时发现后序遍历中对应的数据偏移了一格,并且顺序也不一样,为673。而3就是这颗右子树的根节点。
重复上述过程,通过后续遍历找到根节点,然后在中序遍历数据中根据根节点拆分成两个部分,同时将对应的后序遍历的数据也拆分成两个部分,重复递归,就可以得到整个二叉树了。
private TreeNode build(int[] in, int instart, int inend, int[] post, int poststart, int postend) { if (instart > inend) { return null; } TreeNode root = new TreeNode(post[postend]); int pos = -1; for (int i = 0; i <= inend; i++) { if (in[i] == post[postend]) { pos = i; } } root.left = build(in, instart, pos - 1, post, poststart, poststart + pos - instart - 1); root.right = build(in, pos + 1, inend, post, poststart + pos - instart, postend - 1); return root; } public TreeNode buildTree(int[] in, int[] post) { return build(in, 0, in.length - 1, post, 0, post.length - 1); }
73. Construct Binary Tree from Preorder and Inorder Traversal
根据后续和中序遍历结果,构建出那颗二叉树。参考:https://siddontang.gitbooks.io/leetcode-solution/content/tree/construct_binary_tree.html
private TreeNode build(int[] pre, int prestart, int preend, int[] in, int instart, int inend) { if (instart > inend) { return null; } TreeNode root = new TreeNode(pre[prestart]); int pos = -1; for (int i = 0; i <= inend; i++) { if (in[i] == pre[prestart]) { pos = i; } } root.left = build(pre, prestart + 1, prestart + pos - instart, in, instart, pos - 1); root.right = build(pre, prestart + pos - instart + 1, preend, in, pos + 1, inend); return root; } public TreeNode buildTree(int[] pre, int[] in) { return build(pre, 0, pre.length - 1, in, 0, in.length - 1); }
7. Binary Tree Serialization
可以把二叉树序列化String,也可以把String版本的二叉树还原成节点版本的二叉树。可参见这篇博客:http://blog.csdn.net/ljiabin/article/details/49474445
public String serialize(TreeNode root) { String res = ""; if (root == null) { return res; } Queue<TreeNode> q = new LinkedList<TreeNode>(); q.offer(root); res += root.val; res += ','; while (!q.isEmpty()) { int length = q.size(); for (int i = 0; i < length; i++) { TreeNode node = q.poll(); if (node.left != null) { q.offer(node.left); res += node.left.val; res += ','; } else { res += "#,"; } if (node.right != null) { q.offer(node.right); res += node.right.val; res += ','; } else { res += "#,"; } } } return res; } public TreeNode deserialize(String data) { if (data == null || data == "") { return null; } String[] res = data.split(","); // 节点i之前null节点的个数 int[] nums = new int[res.length]; TreeNode[] arr = new TreeNode[res.length]; for (int i = 0; i < res.length; i++) { if (i > 0) { nums[i] = nums[i - 1]; } if (res[i].equals("#")) { arr[i] = null; nums[i]++; } else { arr[i] = new TreeNode(Integer.parseInt(res[i])); } } for (int i = 0; i < res.length; i++) { if (arr[i] != null) { arr[i].left = arr[(i - nums[i]) * 2 + 1]; arr[i].right = arr[(i - nums[i]) * 2 + 2]; } } return arr[0]; }
475. Binary Tree Maximum Path Sum II
找到一个二叉树从root到叶子节点的最大的一个路径和,非常简单的递归,但是需要考虑的问题是,节点可能是负数。所以每次返回的时候,是选择(左节点,右节点,0)的最大值:
public int maxPathSum2(TreeNode root) { if (root == null) { return 0; } return root.val + Math.max(0, Math.max(maxPathSum2(root.left), maxPathSum2(root.right))); }
94. Binary Tree Maximum Path Sum
求一个二叉树的最大路径和,可以从任意节点到任意节点。
最优路径上的节点一定是连续的,不能中断
最优路径中一定包含某个子树的根节点
写一个递归函数,实现计算根节点到任意点的最大路径和,以及穿过根节点的最大路径和,用一个全局变量保存最优解。
需要注意的是,节点可能会包含负数,所以计算的时候,要判断一下负数。
private int res = Integer.MIN_VALUE; private int helper(TreeNode root) { if (root == null) { return Integer.MIN_VALUE; } // divide int left = helper(root.left); int right = helper(root.right); // conquer int root2any = Math.max(Math.max(left, right), 0) + root.val; int any2any = Math.max(0, left) + Math.max(0, right) + root.val; res = Math.max(res, Math.max(root2any, any2any)); return root2any; } public int maxPathSum(TreeNode root) { if (root == null) { return Integer.MIN_VALUE; } helper(root); return res; }
448. Inorder Successor in Binary Search Tree
找到一个节点的中序后继节点。我的思路是先通过中序遍历得到一个有序的数组,然后再在这个数组中二分查找,找到那个节点。这个算法比九章的标准答案还要快些
private void inorder(TreeNode root, ArrayList<TreeNode> res) { if (root != null) { inorder(root.left, res); res.add(root); inorder(root.right, res); } } private int binarySearch(ArrayList<TreeNode> res, int val) { int start = 0, end = res.size() - 1; while (start + 1 < end) { int mid = start + (end - start) / 2; if (res.get(mid).val == val) { if (mid + 1 < res.size()) { return mid + 1; } else { return -1; } } else if (val > res.get(mid).val) { start = mid; } else { end = mid; } } if (res.get(start).val == val && start + 1 < res.size()) { return start + 1; } if (res.get(end).val == val && end + 1 < res.size()) { return end + 1; } return -1; } public TreeNode inorderSuccessor(TreeNode root, TreeNode p) { ArrayList<TreeNode> res = new ArrayList(); if (root == null || p == null) { return null; } inorder(root, res); int pos = binarySearch(res, p.val); if (pos != -1) { return res.get(pos); } return null; }
95. Validate Binary Search Tree
判断一颗二叉树是不是合法的二分查找树,这时可以用到一个性质,如果它的中序遍历的结果是非递减的,拿它就是合法的:
private void inorder(TreeNode root, ArrayList<Integer> list) { if (root != null) { inorder(root.left, list); list.add(root.val); inorder(root.right, list); } } public boolean isValidBST(TreeNode root) { ArrayList<Integer> list = new ArrayList(); inorder(root, list); for (int i = 1; i < list.size(); i++) { if (list.get(i) <= list.get(i - 1)) { return false; } } return true; }
86. Binary Search Tree Iterator
算是一道系统设计题,给定一些函数接口,要你按照要求实现。实现一个iterator可以遍历二叉树。我用的是中序遍历,把整个树保存在一个ArrayList中,然后用一个pos变量记录当前位置。比九章的标准答案还要快一点:
/** * Definition of TreeNode: * public class TreeNode { * public int val; * public TreeNode left, right; * public TreeNode(int val) { * this.val = val; * this.left = this.right = null; * } * } * Example of iterate a tree: * BSTIterator iterator = new BSTIterator(root); * while (iterator.hasNext()) { * TreeNode node = iterator.next(); * do something for node * } */public class BSTIterator { private ArrayList<TreeNode> arr = new ArrayList<TreeNode>(); private int pos = -1; //@param root: The root of binary tree. private void inorder(TreeNode root) { if (root != null) { inorder(root.left); arr.add(root); inorder(root.right); } } public BSTIterator(TreeNode root) { inorder(root); if (arr.size() > 0) { pos = 0; } } //@return: True if there has next node, or false public boolean hasNext() { return pos >= 0 && pos < arr.size(); } //@return: return next node public TreeNode next() { return arr.get(pos++); }}
此外,Chapter之外的二叉树还有这么一些题目:
175. Invert Binary Tree
反转二叉树,HomeBrew的创始人就是倒在了这道题下,用递归做很简单,先把根节点的左右子树对调,然后再递归得对左右子树调用递归。递归返回条件就是当前节点为空。
public void invertBinaryTree(TreeNode root) { if (root == null) { return; } TreeNode tmp = root.left; root.left = root.right; root.right = tmp; invertBinaryTree(root.left); invertBinaryTree(root.right); }
480. Binary Tree Paths
要求返回所有从根节点到叶子节点的路径。这种要求所有路径的,一看就基本知道八九成是用DFS来做了:
private void dfs(List<String> res, String path, TreeNode root) { if (root.left == null && root.right == null) { path += root.val; res.add(path); return; } if (root.left != null) { dfs(res, path + root.val + "->", root.left); } if (root.right != null) { dfs(res, path + root.val + "->", root.right); } } public List<String> binaryTreePaths(TreeNode root) { List<String> res = new ArrayList(); if (root == null) { return res; } dfs(res, "", root); return res; }
245. Subtree
判断一棵树A是否包含另一棵树B,用DFS遍历A的每个节点,对于A的每个节点,调用一个equal函数判断A的这个节点的子树和B树是否完全相等。
private void dfs(TreeNode T1, TreeNode T2) { if (T1 != null) { if (equal(T1, T2)) { flag = true; return; } dfs(T1.left, T2); dfs(T1.right, T2); } } public boolean isSubtree(TreeNode T1, TreeNode T2) { if (T2 == null) { return true; } dfs(T1, T2); return flag; } private boolean equal(TreeNode T1, TreeNode T2) { // 两个都为空 if (T1 == null && T2 == null) { return true; } // 只有一个为空 if (T1 == null || T2 == null) { return false; } // 都不空,且不相等的时候,就返回false if (T1.val != T2.val) { return false; } // 相等,则进一步判断 return equal(T1.left, T2.left) && equal(T1.right, T2.right); }
453. Flatten Binary Tree to Linked List
要求把一棵树按照先根遍历的规则,转换为一个只有右子树的数:
1 \ 1 2 / \ \ 2 5 => 3 / \ \ \ 3 4 6 4 \ 5 \ 6
private TreeNode p = null; private void inorder(TreeNode root) { if (root != null) { if (p != null) { p.right = root; p.left = null; <span style="font-family: Arial, Helvetica, sans-serif;">// 这一行代码不能少!</span> } p = root; TreeNode r = root.right; // 这一行代码不能少! inorder(root.left); inorder(r); } } public void flatten(TreeNode root) { inorder(root); }注意每次遍历是把上个节点和当前节点建立联系。如果上个节点存在,则直接把上个节点的右子树指向当前节点。然后把p指向当前节点,并把右子树先拿出来(这点很重要,不拿出来基本就是stackoverflow了),再对左右子树分别进行子递归。
177. Convert Sorted Array to Binary Search Tree With Minimal Height
把一个有序数组转换为一颗高度最小的二叉搜索树。思路很简单,递归建树,每次递归都选择数组的中点建树。
private TreeNode build(int[] arr, int start, int end, TreeNode root) { if (start <= end) { int mid = start + (end - start) / 2; root = new TreeNode(arr[mid]); root.left = build(arr, start, mid - 1, root.left); root.right = build(arr, mid + 1, end, root.right); } return root; } public TreeNode sortedArrayToBST(int[] A) { TreeNode root = null; root = build(A, 0, A.length - 1, root); return root; }
140. Fast Power
Calculate the an % b where a, b and n are all 32bit integers.
For 231 % 3 = 2
For 1001000 % 1000 = 0
首先可以参考下百度百科里对于取模运算的定义:http://baike.baidu.com/view/4887065.htm
我们发现,取模运算有这么些规律:
(a * b) % p = (a % p * b % p) % p
public int fastPower(int a, int b, int n) { if (n == 1) { return a % b; } if (n == 0) { return 1 % b; } long res = fastPower(a, b, n / 2); res = res * res % b; if (n % 2 == 1) { res = res * a % b % b; } return (int)res; }
428. Pow(x, n)
这道题与上面那道题有异曲同工之妙,不过推导公式没有上面那么复杂了。也是分治法,需要考虑n小于0的情况,还有分奇偶的情况。如果用分治法则时间复杂度是O(logn),如果是直接用从n递归到n-1再递归到n-2···这种方法,则时间复杂度是O(N)
public double myPow(double x, int n) { if (n == 0) { return 1.0; } if (n < 0) { return 1.0 / myPow(x, -1 * n); } double half = myPow(x, n / 2); if (n % 2 == 1) { return x * half * half; } return half * half; }
- LintCode二叉树&递归分治题总结
- 二叉树专题-lintcode非递归遍历与总结
- LintCode-分治-验证二叉查找树
- lintcode 二叉树总结
- lintcode 二叉树总结
- LintCode-二叉树专题总结
- lintcode 二叉查找树总结
- lintcode二叉查找树总结
- LintCode--翻转二叉树(非递归)
- 二叉树后续非递归遍历-lintcode
- Lintcode-递归-93 平衡二叉树
- LintCode 第97题 二叉树的最大深度 【分治算法】
- LintCode-分治-二叉树中的最大路径和
- 二叉树专题-lintcode递归与非递归遍历
- lintcode递归总结
- lintcode——二叉树总结
- LintCode 关于二叉树问题的总结
- LintCode-二叉查找树专题总结
- ArchLinux必备命令记录
- 使用wsimport生成webservices客户端代码
- 全屏/非全屏切换
- Liunx(一场不可思议的旅行作业)
- Hadoop学习(1):关键技术概要
- LintCode二叉树&递归分治题总结
- Mesos源码分析(8): Mesos-Slave的初始化
- Session解析及运行
- 网络
- Hadoop学习(2):HDFS基础
- 数据类型的取值范围
- QT 的信号与槽机制介绍
- Leetcode : Gray Code
- EventBus使用详解(一)——初步使用EventBus