1.binary-tree-preorder-traversal(二叉树的前序遍历)根-左-右
给出一棵二叉树,返回其节点值的前序遍历。
非递归解法【要记住】:
/** * 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; * } * } */ public class Solution { /** * @param root: The root of binary tree. * @return: Preorder in ArrayList which contains node values. */ public ArrayList<Integer> preorderTraversal(TreeNode root) { // write your code here Stack<TreeNode> stack = new Stack<TreeNode>(); ArrayList<Integer> preorder = new ArrayList<Integer>(); if (root == null) { return preorder; } stack.push(root); while (!stack.empty()) { TreeNode node = stack.pop(); preorder.add(node.val); if (node.right != null) { stack.push(node.right); } if (node.left != null) { stack.push(node.left); } } return preorder; } }
由于stack的先进后出特性要注意先push node.right 后push node.left。
递归解法:
public class Solution { /** * @param root: The root of binary tree. * @return: Preorder in ArrayList which contains node values. */ public ArrayList<Integer> preorderTraversal(TreeNode root) { // write your code here ArrayList<Integer> preorder = new ArrayList<Integer>(); traverse(root, preorder); return preorder; } private void traverse(TreeNode root, ArrayList<Integer> preorder) { if (root == null) { return; } preorder.add(root.val); traverse(root.left, preorder); traverse(root.right, preorder); } }
分治解法:
public class Solution { /** * @param root: The root of binary tree. * @return: Preorder in ArrayList which contains node values. */ public ArrayList<Integer> preorderTraversal(TreeNode root) { // write your code here ArrayList<Integer> preorder = new ArrayList<Integer>(); if (root == null) { return preorder; } ArrayList<Integer> left = preorderTraversal(root.left); ArrayList<Integer> right = preorderTraversal(root.right); preorder.add(root.val); preorder.addAll(left); preorder.addAll(right); return preorder; } }
add()和addAll()的区别和使用
2.binary-tree-inorder-traversal(二叉树的中序遍历)左-根-右
给出一棵二叉树,返回其中序遍历。
非递归解法【要记住】:
/** * 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; * } * } */ public class Solution { /** * @param root: The root of binary tree. * @return: Inorder in ArrayList which contains node values. */ public ArrayList<Integer> inorderTraversal(TreeNode root) { // write your code here Stack<TreeNode> stack = new Stack<TreeNode>(); ArrayList<Integer> inorder= new ArrayList<Integer>(); TreeNode curt = root; while (curt != null || !stack.empty()) { while (curt != null) { stack.push(curt); curt = curt.left; } curt = stack.pop(); inorder.add(curt.val); curt = curt.right; } return inorder; } }
curt的使用。
分治:
public class Solution { /** * @param root: The root of binary tree. * @return: Inorder in ArrayList which contains node values. */ public ArrayList<Integer> inorderTraversal(TreeNode root) { // write your code here ArrayList<Integer> inorder = new ArrayList<Integer>(); if (root == null) { return inorder; } ArrayList<Integer> left = inorderTraversal(root.left); ArrayList<Integer> right = inorderTraversal(root.right); inorder.addAll(left); inorder.add(root.val); inorder.addAll(right); return inorder; } }
3.binary-tree-postorder-traversal(二叉树的后序遍历)左- 右- 根
给出一棵二叉树,返回其节点值的后序遍历。
迭代解法【要记住】:
/** * 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; * } * } */ public class Solution { /** * @param root: The root of binary tree. * @return: Postorder in ArrayList which contains node values. */ public ArrayList<Integer> postorderTraversal(TreeNode root) { // write your code here Stack<TreeNode> stack = new Stack<TreeNode>(); ArrayList<Integer> postorder = new ArrayList<Integer>(); TreeNode prev = null; TreeNode curt = root; if (root == null) { return postorder; } stack.push(root); while (!stack.empty()) { curt = stack.peek(); if (prev == null || prev.left == curt || prev.right == curt) { if (curt.left != null) { stack.push(curt.left); } else if (curt.right != null) { stack.push(curt.right); } } else if (curt.left == prev) { if (curt.right != null) { stack.push(curt.right); } } else { postorder.add(curt.val); stack.pop(); } prev = curt; } return postorder; } }
curt和prev的使用。分三种情况讨论:沿着树向下遍历、从左向上遍历树和其他。
分治解法:
public class Solution { /** * @param root: The root of binary tree. * @return: Postorder in ArrayList which contains node values. */ public ArrayList<Integer> postorderTraversal(TreeNode root) { // write your code here ArrayList<Integer> postorder = new ArrayList<Integer>(); if (root == null) { return postorder; } ArrayList<Integer> left = postorderTraversal(root.left); ArrayList<Integer> right = postorderTraversal(root.right); postorder.addAll(left); postorder.addAll(right); postorder.add(root.val); return postorder; } }
4.maximum-depth-of-binary-tree(二叉树的最大深度)
给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的距离。
分治解法:
public class Solution { /** * @param root: The root of binary tree. * @return: An integer. */ public int maxDepth(TreeNode root) { // write your code here if (root == null) { return 0; } int left = maxDepth(root.left); int right = maxDepth(root.right); return Math.max(left, right) + 1; } }
遍历解法:
public class Solution { /** * @param root: The root of binary tree. * @return: An integer. */ private int depth = Integer.MIN_VALUE; public int maxDepth(TreeNode root) { // write your code here if (root == null) { return 0; } helper(root, 1); return depth; } private void helper(TreeNode root, int curtDepth) { if (root == null) { return; } if (curtDepth > depth) { depth = curtDepth; } helper(root.left, curtDepth + 1); helper(root.right, curtDepth + 1); } }
遍历解法一般都会有helper()函数帮助,需要全局变量depth记录最大深度。
5.minimum-depth-of-binary-tree(二叉树的最小深度)
给定一个二叉树,找出其最小深度。二叉树的最小深度为根节点到最近叶子节点的距离。
public class Solution { /** * @param root: The root of binary tree. * @return: An integer. */ public int minDepth(TreeNode root) { // write your code here if (root == null) { return 0; } return getMin(root); } private int getMin(TreeNode root) { if (root == null) { return Integer.MAX_VALUE; } int left = getMin(root.left); int right = getMin(root.right); if (root.left == null && root.right == null) { return 1; } return Math.min(left, right) + 1; } }
注意:getMin()函数中,if(root == null){return Integer.MAX_VALUE;} 遇到叶子结点结束,if(root.left == null && root.right == null){return 1;}
6.binary-tree-paths(二叉树的所有路径)
给一棵二叉树,找出从根节点到叶子节点的所有路径。
分治解法:
public class Solution { /** * @param root the root of the binary tree * @return all root-to-leaf paths */ public List<String> binaryTreePaths(TreeNode root) { // Write your code here List<String> results = new ArrayList<String>(); if (root == null) { return results; } List<String> leftResults = binaryTreePaths(root.left); List<String> rightResults = binaryTreePaths(root.right); for (String result : leftResults) { results.add(root.val + "->" + result); } for (String result : rightResults) { results.add(root.val + "->" + result); } if (results.size() == 0) { results.add("" + root.val); } return results; } }
遍历解法:
public class Solution { /** * @param root the root of the binary tree * @return all root-to-leaf paths */ public List<String> binaryTreePaths(TreeNode root) { // Write your code here List<String> paths = new ArrayList<String>(); if (root == null) { return paths; } helper(root, String.valueOf(root.val), paths); return paths; } private void helper(TreeNode root, String path, List<String> paths) { if (root == null) { return; } if (root.left == null && root.right == null) { paths.add(path); return; } if (root.left != null) { helper(root.left, path + "->" + String.valueOf(root.left.val), paths); } if (root.right != null) { helper(root.right, path + "->" + String.valueOf(root.right.val), paths); } } }
注意:private void helper(TreeNode root, String path, List<String> paths) {}
7.minimum-subtree(最小和子树)
给定一个二叉树,找到具有最小和的子树。 返回子树的根。保证只有一个具有最小和的子树,给定的二叉树不是空树。
分治+遍历解法:
public class Solution { private TreeNode subtree = null; private int subtreeSum = Integer.MAX_VALUE; /** * @param root the root of binary tree * @return the root of the minimum subtree */ public TreeNode findSubtree(TreeNode root) { // Write your code here helper(root); return subtree; } private int helper(TreeNode root) { if (root == null) { return 0; } int sum = helper(root.left) + helper(root.right) + root.val; if (sum < subtreeSum) { subtreeSum = sum; subtree = root; } return sum; } }
注意:全局变量TreeNode subtree和int subtreeSum进行记录。
纯分治解法:
class ResultType { public TreeNode subtree; public int sum; public int minSum; public ResultType(TreeNode subtree, int sum, int minSum) { this.subtree = subtree; this.sum = sum; this.minSum = minSum; } } public class Solution { /** * @param root the root of binary tree * @return the root of the minimum subtree */ public TreeNode findSubtree(TreeNode root) { // Write your code here ResultType result = helper(root); return result.subtree; } private ResultType helper(TreeNode root) { if (root == null) { return new ResultType(null, 0, Integer.MAX_VALUE); } ResultType leftResult = helper(root.left); ResultType rightResult = helper(root.right); ResultType result = new ResultType( root, leftResult.sum + rightResult.sum + root.val, leftResult.sum + rightResult.sum + root.val); if (leftResult.minSum < result.minSum) { result.minSum = leftResult.minSum; result.subtree = leftResult.subtree; } if (rightResult.minSum < result.minSum) { result.minSum = rightResult.minSum; result.subtree = rightResult.subtree; } return result; } }
注意:class ResultType{int var1,var2;}的使用。在求最大/最小值时,赋初值Integer.MIN_VALUE/Integer.MAX_VALUE。
8.balanced-binary-tree(平衡二叉树)
给定一个二叉树,确定它是高度平衡的。对于这个问题,一棵高度平衡的二叉树的定义是:一棵二叉树中每个节点的两个子树的深度相差不会超过1。
不使用ResultType的解法:
public class Solution { /** * @param root: The root of binary tree. * @return: True if this Binary tree is Balanced, or false. */ public boolean isBalanced(TreeNode root) { // write your code here return maxDepth(root) != -1; } private int maxDepth(TreeNode root) { if (root == null) { return 0; } int left = maxDepth(root.left); int right = maxDepth(root.right); if (left == -1 || right == -1 || Math.abs(left - right) > 1) { return -1; } return Math.max(left, right) + 1; } }
使用ResultType的解法:
/** * 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; * } * } */ class ResultType { public boolean isBalanced; public int maxDepth; public ResultType(boolean isBalanced, int maxDepth) { this.isBalanced = isBalanced; this.maxDepth = maxDepth; } } public class Solution { /** * @param root: The root of binary tree. * @return: True if this Binary tree is Balanced, or false. */ public boolean isBalanced(TreeNode root) { return helper(root).isBalanced; } private ResultType helper(TreeNode root) { if (root == null) { return new ResultType(true, 0); } ResultType left = helper(root.left); ResultType right = helper(root.right); // subtree not balance, root not balance if (!left.isBalanced || !right.isBalanced || Math.abs(left.maxDepth - right.maxDepth) > 1) { return new ResultType(false, -1); } return new ResultType(true, Math.max(left.maxDepth, right.maxDepth) + 1); } }
注意:class ResultType {public boolean isBalanced; public int maxDepth}记录是否为平衡二叉树和树的最大深度。
9.subtree-with-maximum-average(具有最大平均值的子树)
给定一个二叉树,找到最大平均值的子树。 返回子树的根。
使用ResultType,分治+遍历的解法:
/** * 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; * } * } */ class ResultType{ public int sum; public int size; public ResultType(int sum, int size) { this.sum = sum; this.size = size; } } public class Solution { /** * @param root the root of binary tree * @return the root of the maximum average of subtree */ private TreeNode subtree = null; private ResultType subtreeResult = null; public TreeNode findSubtree2(TreeNode root) { // Write your code here helper(root); return subtree; } private ResultType helper(TreeNode root) { if (root == null) { return new ResultType(0, 0); } ResultType left = helper(root.left); ResultType right = helper(root.right); ResultType result = new ResultType( left.sum + right.sum + root.val, left.size + right.size + 1 ); if (subtree == null || subtreeResult.sum * result.size < result.sum * subtreeResult.size ) { subtree = root; subtreeResult = result; } return result; } }
10.flatten-binary-tree-to-linked-list(将二叉树拆成链表)
将一棵二叉树按照前序遍历拆解成为一个假链表
。所谓的假链表是说,用二叉树的 right 指针,来表示链表中的 next 指针。不要忘记将左儿子标记为 null,否则你可能会得到空间溢出或是时间溢出。
遍历解法:
public class Solution { /** * @param root: a TreeNode, the root of the binary tree * @return: nothing */ private TreeNode lastNode = null; public void flatten(TreeNode root) { // write your code here if (root == null) { return; } if (lastNode != null) { lastNode.left = null; lastNode.right = root; } lastNode = root; TreeNode right = root.right; flatten(root.left); flatten(right); } }
注意:定义lastNode记录上一个被访问的节点。当lastNode不为空时,将lastNode的左儿子置空,右儿子置当前root。根据题目要求的前序遍历方法,要保存当前root的右子树,然后先拆解左子树,再拆解右子树。
非递归解法:
public class Solution { /** * @param root: a TreeNode, the root of the binary tree * @return: nothing */ public void flatten(TreeNode root) { // write your code here Stack<TreeNode> stack = new Stack<TreeNode>(); if (root == null) { return; } stack.push(root); while (!stack.empty()) { TreeNode node = stack.pop(); if (node.right != null) { stack.push(node.right); } if (node.left != null) { stack.push(node.left); } //connect node.left = null; if (stack.empty()) { node.right = null; } else { node.right = stack.peek(); } } } }
注意:在非递归前序遍历的基础上添加connect:当前node=stack.pop()的左儿子置空,右儿子置stack.peek()。
LCA最近公共祖先
11.lowest-common-ancestor(最近公共祖先)【高频题】
给定一棵二叉树,找到两个节点的最近公共父节点(LCA)。最近公共祖先是两个节点的公共的祖先节点且具有最大深度。假设给出的两个节点都在树中存在。
分治解法:
public class Solution { /** * @param root: The root of the binary search tree. * @param A and B: two nodes in a Binary. * @return: Return the least common ancestor(LCA) of the two nodes. */ public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) { // write your code here if (root == null || root == A || root == B) { return root; } TreeNode left = lowestCommonAncestor(root.left, A, B); TreeNode right = lowestCommonAncestor(root.right, A, B); if (left != null && right != null) { return root; } if (left != null) { return left; } if (right != null){ return right; } return null; } }
注意:在root为根的二叉树中找A,B的LCA;如果找到了就返回这个LCA,如果只碰到A,就返回A;如果只碰到B,就返回B;如果都没有,就返回null。
12.lowest-common-ancestor-ii(最近公共祖先II)
给一棵二叉树和二叉树中的两个节点,找到这两个节点的最近公共祖先LCA
。两个节点的最近公共祖先,是指两个节点的所有父亲节点中(包括这两个节点),离这两个节点最近的公共的节点。每个节点除了左右儿子指针以外,还包含一个父亲指针parent
,指向自己的父亲。
跟第10题同样的方法也可解:
/** * Definition of ParentTreeNode: * * class ParentTreeNode { * public ParentTreeNode parent, left, right; * } */ public class Solution { /** * @param root: The root of the tree * @param A, B: Two node in the tree * @return: The lowest common ancestor of A and B */ public ParentTreeNode lowestCommonAncestorII(ParentTreeNode root, ParentTreeNode A, ParentTreeNode B) { // Write your code here if (root == null || root == A || root == B) { return root; } ParentTreeNode left = lowestCommonAncestorII(root.left, A, B); ParentTreeNode right = lowestCommonAncestorII(root.right, A, B); if (left != null && right != null) { return root; } if (left != null) { return left; } if (right != null){ return right; } return null; } }
或者:
/** * Definition of ParentTreeNode: * * class ParentTreeNode { * public ParentTreeNode parent, left, right; * } */ public class Solution { /** * @param root: The root of the tree * @param A, B: Two node in the tree * @return: The lowest common ancestor of A and B */ public ParentTreeNode lowestCommonAncestorII(ParentTreeNode root, ParentTreeNode A, ParentTreeNode B) { // Write your code here ArrayList<ParentTreeNode> pathA = getPath(A); ArrayList<ParentTreeNode> pathB = getPath(B); int sizeA = pathA.size() - 1; int sizeB = pathB.size() - 1; ParentTreeNode lowestAncestor = null; while (sizeA >= 0 && sizeB >= 0) { if (pathA.get(sizeA) != pathB.get(sizeB)) { break; } lowestAncestor = pathA.get(sizeA); sizeA--; sizeB--; } return lowestAncestor; } private ArrayList<ParentTreeNode> getPath(ParentTreeNode node) { ArrayList<ParentTreeNode> path = new ArrayList<ParentTreeNode>(); while (node != null) { path.add(node); node = node.parent; } return path; } }
注意:利用parent指针自底向上记录A,B的路径,自顶向下找最后一个相同的节点即为要求的点。
13.lowest-common-ancestor-iii(最近公共祖先III)
给一棵二叉树和二叉树中的两个节点,找到这两个节点的最近公共祖先LCA。两个节点的最近公共祖先,是指两个节点的所有父亲节点中(包括这两个节点),离这两个节点最近的公共的节点。返回 null
如果两个节点在这棵树上不存在最近公共祖先的话。这两个节点未必都在这棵树上出现。
/** * 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; * } * } */ class ResultType{ public boolean a_exist; public boolean b_exist; public TreeNode node; public ResultType(boolean a, boolean b, TreeNode node) { this.a_exist = a; this.b_exist = b; this.node = node; } } public class Solution { /** * @param root The root of the binary tree. * @param A and B two nodes * @return: Return the LCA of the two nodes. */ public TreeNode lowestCommonAncestor3(TreeNode root, TreeNode A, TreeNode B) { // write your code here ResultType result = helper(root, A, B); if (result.a_exist && result.b_exist) { return result.node; } else { return null; } } private ResultType helper(TreeNode root, TreeNode A, TreeNode B) { if (root == null) { return new ResultType(false, false, null); } ResultType leftResult = helper(root.left, A, B); ResultType rightResult = helper(root.right, A, B); boolean a_exist = leftResult.a_exist || rightResult.a_exist || root == A; boolean b_exist = leftResult.b_exist || rightResult.b_exist || root == B; if (root == A || root == B) { return new ResultType(a_exist, b_exist, root); } if (leftResult.node != null && rightResult.node != null) { return new ResultType(a_exist, b_exist, root); } if (leftResult.node != null) { return new ResultType(a_exist, b_exist, leftResult.node); } if (rightResult.node != null) { return new ResultType(a_exist, b_exist, rightResult.node); } return new ResultType(a_exist, b_exist, null); } }
注意:使用ResultType{boolean a_exist,b_exist;TreeNode node}判断A和B节点是否都存在;然后在以root为根的二叉树中找A,B的LCA;如果找到了就返回这个LCA,如果只碰到A,就返回A;如果只碰到B,就返回B;如果都没有,就返回null。
LCS最长连续序列
14.binary-tree-longest-consecutive-sequence(最长连续序列)
给定二叉树,找到最长连续序列路径的长度并返回。该路径是指从某个起始节点到父子连接树中节点的任意节点序列。 最长的连续路径需要从父母到孩子(不能相反)。
分治+遍历解法:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ public class Solution { /** * @param root the root of binary tree * @return the length of the longest consecutive sequence path */ private int longest = Integer.MIN_VALUE; public int longestConsecutive(TreeNode root) { // Write your code here helper(root); return longest; } private int helper(TreeNode root) { if (root == null) { return 0; } int left = helper(root.left); int right = helper(root.right); int subtreeLongest = 1; if (root.left != null && root.val + 1 == root.left.val) { subtreeLongest = Math.max(subtreeLongest, left + 1); } if (root.right != null && root.val + 1 == root.right.val) { subtreeLongest = Math.max(subtreeLongest, right + 1); } if (subtreeLongest > longest) { longest = subtreeLongest; } return subtreeLongest; } }
使用全局变量longest存储最大长度。如果是连续序列,则root.val + 1 == root.left(right).val。
15.binary-tree-longest-consecutive-sequence-ii(最长连续序列II)
给定二叉树,找到最长连续序列路径的长度并返回。该路径可以在树中的任何节点处开始和结束。
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class ResultType { public int max_length; public int max_down; public int max_up; public ResultType(int length, int down, int up) { this.max_length = length; this.max_down = down; this.max_up = up; } } public class Solution { /** * @param root the root of binary tree * @return the length of the longest consecutive sequence path */ public int longestConsecutive2(TreeNode root) { // Write your code here return helper(root).max_length; } private ResultType helper(TreeNode root) { if (root == null) { return new ResultType(0, 0, 0); } ResultType left = helper(root.left); ResultType right = helper(root.right); int down = 0; int up = 0; if (root.left != null && root.left.val + 1 == root.val) { down = Math.max(down, left.max_down + 1); } if (root.left != null && root.left.val - 1 == root.val) { up = Math.max(up, left.max_up + 1); } if (root.right != null && root.right.val + 1 == root.val) { down = Math.max(down, right.max_down + 1); } if (root.right != null && root.right.val - 1 == root.val) { up = Math.max(up, right.max_up + 1); } int len = down + 1 + up; len = Math.max(len, Math.max(left.max_length, right.max_length)); return new ResultType(len, down, up); } }
注意:这个问题中拐点很重要。上升和下降序列和拐点拼在一起才是完整的序列。使用ResultType{int max_length,max_down,max_up}储存结果。
len = Math.max(len, Math.max(left.max_length, right.max_length));先求左右子树中的最大长度,然后最终的最大长度。
16.binary-tree-longest-consecutive-sequence-iii(最长连续序列III)
最长连续序列II的后续问题。给定一个k-ary树,找到最长连续序列路径的长度并返回。该路径可以在树中的任何节点处开始和结束。
/** * Definition for a multi tree node. * public class MultiTreeNode { * int val; * List<TreeNode> children; * MultiTreeNode(int x) { v(al = x; } * } */ class ResultType { public int max_len; public int max_down; public int max_up; public ResultType(int length, int down, int up) { this.max_len = length; this.max_down = down; this.max_up = up; } } public class Solution { /** * @param root the root of k-ary tree * @return the length of the longest consecutive sequence path */ public int longestConsecutive3(MultiTreeNode root) { // Write your code here return helper(root).max_len; } private ResultType helper(MultiTreeNode root) { if (root == null) { return new ResultType(0, 0, 0); } int down = 0; int up = 0; int max_len = 1; for (MultiTreeNode node : root.children) { ResultType result = helper(node); if (node.val + 1 == root.val) { down = Math.max(down, result.max_down + 1); } if (node.val - 1 == root.val) { up = Math.max(up, result.max_up + 1); } max_len = Math.max(max_len, result.max_len); } max_len = Math.max(down + 1 + up, max_len); return new ResultType(max_len, down, up); } }
注意:与II思路类似。
for (MultiTreeNode node : root.children) {
ResultType result = helper(node);
.......
max_len = Math.max(max_len, result.max_len);//chidren节点中的最大长度
}
max_len = Math.max(down + 1 + up, max_len);//最终的最大长度
二叉树的路径和(找出所有路径中各节点相加总和值等于目标值的路径)
17.binary-tree-path-sum(二叉树的路径和)
给定一个二叉树,找出所有路径中各节点相加总和等于给定 目标值
的路径。一个有效的路径,指的是从根节点到叶节点的路径。
/** * 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; * } * } */ public class Solution { /** * @param root the root of binary tree * @param target an integer * @return all valid paths */ public List<List<Integer>> binaryTreePathSum(TreeNode root, int target) { // Write your code here List<List<Integer>> paths = new ArrayList<List<Integer>>(); if (root == null) { return paths; } ArrayList<Integer> path = new ArrayList<Integer>(); path.add(root.val); helper(root, path, root.val, target, paths); return paths; } private void helper(TreeNode root, ArrayList<Integer> path, int sum, int target, List<List<Integer>> paths) { if (root.left == null && root.right == null) { if (sum == target) { paths.add(new ArrayList<Integer>(path)); } } if (root.left != null) { path.add(root.left.val); helper(root.left, path, sum + root.left.val, target, paths); path.remove(path.size() - 1); } if (root.right != null) { path.add(root.right.val); helper(root.right, path, sum + root.right.val, target, paths); path.remove(path.size() - 1); } } }
注意:跟subsets有相似点(遇到叶子结点时若满足条件sum=target就加入results,没遇到叶子结点就继续DFS)。
private void helper(TreeNode root, ArrayList<Integer> path, int sum, int target, List<List<Integer>> paths)
18.binary-tree-path-sum-ii(二叉树的路径和II)
给一棵二叉树和一个目标值,设计一个算法找到二叉树上的和为该目标值的所有路径。路径可以从任何节点出发和结束,但是需要是一条一直往下走的路线。也就是说,路径上的节点的层级是逐个递增的。
/** * 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; * } * } */ public class Solution { /** * @param root the root of binary tree * @param target an integer * @return all valid paths */ public List<List<Integer>> binaryTreePathSum2(TreeNode root, int target) { // Write your code here List<List<Integer>> paths = new ArrayList<List<Integer>>(); if (root == null) { return paths; } ArrayList<Integer> buffer = new ArrayList<Integer>(); helper(root, target, buffer, 0, paths); return paths; } private void helper(TreeNode root, int target, ArrayList<Integer> buffer, int level, List<List<Integer>> paths) { if (root == null) { return; } int temp = target; buffer.add(root.val); for (int i = level; i >= 0; i--) { temp -= buffer.get(i); if (temp == 0) { ArrayList<Integer> path = new ArrayList<Integer>(); for (int j = i; j <= level; j++) { path.add(buffer.get(j)); } paths.add(path); } } helper(root.left, target, buffer, level + 1, paths); helper(root.right, target, buffer, level + 1, paths); buffer.remove(buffer.size() - 1); } }
注意:一层一层自底向上寻找路径,找到后自顶向下进行添加。
public void helper(TreeNode root, int sum, ArrayList<Integer> path, int level, List<List<Integer>> paths) { int temp = sum; ... //自底向上寻找路径 for (int i = level;i >=0; i--) { temp -= path.get(i); if (temp == 0) { //自顶向下进行添加 for(int j = i; j <= level; j++) { ... } } }
19.binary-tree-path-sum-iii(二叉树的路径和III)【hard】
给一棵二叉树和一个目标值,找到二叉树上所有的和为该目标值的路径。路径可以从二叉树的任意节点出发,任意节点结束。
/** * Definition of ParentTreeNode: * * class ParentTreeNode { * public int val; * public ParentTreeNode parent, left, right; * } */ public class Solution { /** * @param root the root of binary tree * @param target an integer * @return all valid paths */ public List<List<Integer>> binaryTreePathSum3(ParentTreeNode root, int target) { // Write your code here List<List<Integer>> results = new ArrayList<List<Integer>>(); dfs(root, target, results); return results; } public void dfs(ParentTreeNode root, int target, List<List<Integer>> results) { if (root == null) { return; } List<Integer> path = new ArrayList<Integer>(); findSum(root, null, target, path, results); dfs(root.left, target, results); dfs(root.right, target, results); } public void findSum(ParentTreeNode root, ParentTreeNode father, int target, List<Integer> path, List<List<Integer>> results) { path.add(root.val); target -= root.val; if (target == 0) { ArrayList<Integer> tmp = new ArrayList<Integer>(); Collections.addAll(tmp, new Integer[path.size()]); Collections.copy(tmp, path); results.add(tmp); } if (root.parent != null && root.parent != father) { findSum(root.parent, root, target, path, results); } if (root.left != null && root.left != father) { findSum(root.left, root, target, path, results); } if (root.right != null && root.right != father) { findSum(root.right, root, target, path, results); } path.remove(path.size() - 1); } }
Binary Search Tree (BST)二叉查找树、二叉搜索树、排序二叉树
20.validate-binary-search-tree(验证二叉查找树)
给定一个二叉树,判断它是否是合法的二叉查找树(BST)。一棵BST定义为:节点的左子树中的值要严格小于该节点的值。节点的右子树中的值要严格大于该节点的值。左右子树也必须是二叉查找树。一个节点的树也是二叉查找树。
分治解法:
/** * 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; * } * } */ class ResultType { public boolean is_bst; public int maxValue; public int minValue; public ResultType(boolean is_bst, int max, int min) { this.is_bst = is_bst; this.maxValue = max; this.minValue = min; } } public class Solution { /** * @param root: The root of binary tree. * @return: True if the binary tree is BST, or false */ public boolean isValidBST(TreeNode root) { // write your code here ResultType r = helper(root); return r.is_bst; } private ResultType helper(TreeNode root) { if (root == null) { return new ResultType(true, Integer.MIN_VALUE, Integer.MAX_VALUE); } ResultType left = helper(root.left); ResultType right = helper(root.right); if (!left.is_bst || !right.is_bst) { return new ResultType(false, 0, 0); } if (root.left != null && left.maxValue >= root.val || root.right != null && right.minValue <= root.val) { return new ResultType(false, 0, 0); } return new ResultType(true, Math.max(root.val, right.maxValue), Math.min(root.val, left.minValue)); } }
注意:使用class ResultType{boolean is_bst; int maxValue; int minValue;...}存储, 利用left.maxValue<root.val<right.minValue进行判断。
21.convert-binary-search-tree-to-doubly-linked-list(将二叉查找树转换成双链表)
将一个二叉查找树按照中序遍历转换成双向链表。
/** * 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; * } * } * Definition for Doubly-ListNode. * public class DoublyListNode { * int val; * DoublyListNode next, prev; * DoublyListNode(int val) { * this.val = val; * this.next = this.prev = null; * } * } */ class ResultType { DoublyListNode first; DoublyListNode last; public ResultType(DoublyListNode first, DoublyListNode last) { this.first = first; this.last = last; } } public class Solution { /** * @param root: The root of tree * @return: the head of doubly list node */ public DoublyListNode bstToDoublyList(TreeNode root) { // Write your code here if (root == null) { return null; } ResultType r = helper(root); return r.first; } private ResultType helper(TreeNode root) { if (root == null) { return null; } ResultType left = helper(root.left); ResultType right = helper(root.right); ResultType result = new ResultType(null, null); DoublyListNode node = new DoublyListNode(root.val); if (left == null) { result.first = node; } else { result.first = left.first; left.last.next = node; node.prev = left.last; } if (right == null) { result.last = node; } else { result.last = right.last; right.first.prev = node; node.next = right.first; } return result; } }
注意:使用class ResultType{DoublyListNode first, DoublyListNode last}记录链表的开始节点和结束节点。左右子链表的链接要着重考虑。
22.inorder-successor-in-binary-search-tree(二叉查找树中序遍历后继)
给一个二叉查找树,以及一个节点,求该节点的中序遍历后继,如果没有返回null。
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ //从root查找p节点的过程,同时保存旧的比p大且相差最小的root节点,作为successor public class Solution { public TreeNode inorderSuccessor(TreeNode root, TreeNode p) { TreeNode successor = null;//记录后继节点 while (root != null && root != p) { //如果当前root比p大,继续查找更小的比p大的root if (root.val > p.val) { successor = root;//保存比p大且在目前相差最小的root root = root.left; } else { root = root.right;//当前root比p小,继续查找更大的比p小的root } } //如果root为空 if (root == null) { return null; } //此时root与p相等,如果p没有右子树,直接返回当前比p大且相差最小的root if (root.right == null) { return successor; } //如果p有右子树,直接找右子树的最小节点(最左下) root = root.right; while (root.left != null) { root = root.left; } return root; } }
注意:整体思路是从root查找p节点的过程,同时保存旧的比p大且相差最小的root节点,作为successor。使用successor记录后继节点,在root不为空且不等于p的时候,如果当前root比p大,继续查找更小的比p大的root,同时保存比p大且在目前相差最小的root;如果当前root比p小,继续查找更大的比p小的root。循环结束后,如果root为空,直接返回null。此时root与p相等,如果p没有右子树,直接返回当前比p大且相差最小的root,如果p有右子树,直接找右子树的最小节点(最左下),返回即可。
23. binary-tree-maximum-path-sum(二叉树的最大路径和)
给出一棵二叉树,寻找一条路径使其路径和最大,路径可以在任一节点中开始和结束(路径和为两个节点之间所在路径上的节点权值之和)。
分治解法:
class ResultType { // singlePath: 从root往下走到任意点的最大路径,这条路径至少包含一个点 // maxPath: 从树中任意到任意点的最大路径,这条路径至少包含一个点 int singlePath; int maxPath; public ResultType(int singlePath, int maxPath) { this.singlePath = singlePath; this.maxPath = maxPath; } } public class Solution { /** * @param root: The root of binary tree. * @return: An integer. */ public int maxPathSum(TreeNode root) { // write your code here ResultType result = helper(root); return result.maxPath; } private ResultType helper(TreeNode root) { if (root == null) { return new ResultType(Integer.MIN_VALUE, Integer.MIN_VALUE); } // Divide ResultType left = helper(root.left); ResultType right = helper(root.right); // Conquer int singlePath = Math.max(0, Math.max(left.singlePath, right.singlePath)) + root.val; int maxPath = Math.max(left.maxPath, right.maxPath); maxPath = Math.max(maxPath, Math.max(left.singlePath, 0) + Math.max(right.singlePath, 0) + root.val); return new ResultType(singlePath, maxPath); } }
注意:
class ResultType {
int singlePath;// singlePath: 从root往下走到任意点的最大路径,这条路径至少包含一个点
int maxPath;// maxPath: 从树中任意到任意点的最大路径,这条路径至少包含一个点
...
}
24. binary-tree-maximum-path-sum-ii(二叉树的最大路径和II)
给一棵二叉树,找出从根节点出发的路径中和最大的一条。这条路径可以在任何二叉树中的节点结束,但是必须包含至少一个点(也就是根了)。
分治解法:
/** * 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; * } * } */ public class Solution { /** * @param root the root of binary tree. * @return an integer */ public int maxPathSum2(TreeNode root) { // Write your code here if (root == null) { return Integer.MIN_VALUE; } int left = maxPathSum2(root.left); int right = maxPathSum2(root.right); return root.val + Math.max(0, Math.max(left, right)); } }
注意: return root.val + Math.max(0, Math.max(left,right));这么写是考虑到二叉树的值也可能为负数,负数加上负数和会越来越小,不如不加直接为0。
25.binary-search-tree-iterator(二叉查找树迭代器)【hard】
设计实现一个带有下列属性的二叉查找树的迭代器:元素按照递增的顺序被访问(比如中序遍历);next()
和hasNext()
的询问操作要求均摊时间复杂度是O(1)
/** * 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 { //@param root: The root of binary tree. private Stack<TreeNode> stack = new Stack<TreeNode>(); private TreeNode node = null; public BSTIterator(TreeNode root) { // write your code here node = root; } //@return: True if there has next node, or false public boolean hasNext() { // write your code here if (node != null) { TreeNode next = node; while (next != null) { stack.push(next); next = next.left; } node = null; } return !stack.empty(); } //@return: return next node public TreeNode next() { // write your code here if (!hasNext()) { return null; } TreeNode curt = stack.pop(); node = curt.right; return curt; } }
26.insert-node-in-a-binary-search-tree(在二叉查找树中插入节点)
给定一棵二叉查找树和一个新的树节点,将节点插入到树中。你需要保证该树仍然是一棵二叉查找树。
分治解法:
/** * 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; * } * } */ public class Solution { /** * @param root: The root of the binary search tree. * @param node: insert this node into the binary search tree * @return: The root of the new binary search tree. */ public TreeNode insertNode(TreeNode root, TreeNode node) { // write your code here if (root == null) { return node; } if (root.val > node.val) { root.left = insertNode(root.left, node); } else { root.right = insertNode(root.right, node); } return root; } }
注意:要插入的节点跟root.val做比较后决定插入左子树还是右子树。if (root == null) {return node;}而不是return null。
27.search-range-in-binary-search-tree(二叉查找树中搜索区间)
给定两个值 k1 和 k2(k1 < k2)和一个二叉查找树的根节点。找到树中所有值在 k1 到 k2 范围内的节点。即打印所有x (k1 <= x <= k2) 其中 x 是二叉查找树的中的节点值。返回所有升序的节点值。
/** * 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; * } * } */ public class Solution { /** * @param root: The root of the binary search tree. * @param k1 and k2: range k1 to k2. * @return: Return all keys that k1<=key<=k2 in ascending order. */ private ArrayList<Integer> result; public ArrayList<Integer> searchRange(TreeNode root, int k1, int k2) { // write your code here result = new ArrayList<Integer>(); helper(root, k1, k2); return result; } private void helper(TreeNode root, int k1, int k2) { if (root == null) { return; } if (root.val > k1) { helper(root.left, k1, k2); } if (root.val >= k1 && root.val <= k2) { result.add(root.val); } if (root.val < k2) { helper(root.right, k1, k2); } } }
注意:因为要返回满足k1 <= x <= k2条件的所有升序x,所以采用中序遍历(左-根-右)。如果root.val > k,helper(root.left, k1, k2);如果root.val >= k1 && root.val <= k2) ,result.add(root.val);如果root.val < k2,helper(root.right, k1, k2)。
28.remove-node-in-binary-search-tree(删除二叉查找树中的节点)【hard】
给定一棵具有不同节点值的二叉查找树,删除树中与给定值相同的节点。如果树中没有相同值的节点,就不做任何处理。你应该保证处理之后的树仍是二叉查找树。
/** * 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; * } * } */ public class Solution { /** * @param root: The root of the binary search tree. * @param value: Remove the node with given value. * @return: The root of the binary search tree after removal. */ public TreeNode removeNode(TreeNode root, int value) { // write your code here TreeNode dummy = new TreeNode(0); dummy.left = root; TreeNode parent = findNode(dummy, root, value); TreeNode node; if (parent.left != null && parent.left.val == value) { node = parent.left; } else if (parent.right != null && parent.right.val == value) { node = parent.right; } else { return dummy.left; } deleteNode(parent, node); return dummy.left; } private TreeNode findNode(TreeNode parent, TreeNode node, int value) { if (node == null) { return parent; } if (node.val == value) { return parent; } if (value < node.val) { return findNode(node, node.left, value); } else { return findNode(node, node.right, value); } } private void deleteNode(TreeNode parent, TreeNode node) { if (node.right == null) { if (parent.left == node) { parent.left = node.left; } else { parent.right = node.left; } } else { TreeNode temp = node.right; TreeNode father = node; while (temp.left != null) { father = temp; temp = temp.left; } if (father.left == temp) { father.left = temp.right; } else { father.right = temp.right; } if (parent.left == node) { parent.left = temp; } else { parent.right = temp; } temp.left = node.left; temp.right = node.right; } } }
29.sort-integers-ii(整数排序II)【要记住】
给一组整数,按照升序排序。使用归并排序,快速排序,堆排序或者任何其他 O(n log n) 的排序算法。
快速排序解法:
public class Solution { /** * @param A an integer array * @return void */ public void sortIntegers2(int[] A) { // Write your code here if (A == null || A.length == 0) { return; } quickSort(A, 0, A.length - 1); } private void quickSort(int[] A, int start, int end) { if (start >= end) { return; } int left = start; int right = end; int pivot = A[start + (end - start) / 2]; while (left <= right) { while (left <= right && A[left] < pivot) { left++; } while (left <= right && A[right] > pivot) { right--; } if (left <= right) { int temp = A[left]; A[left] = A[right]; A[right] = temp; left++; right--; } } quickSort(A, start, right); quickSort(A, left, end); } }
思想:分治,先整体有序再局部有序。1.从序列中挑出一个元素,作为基准(pivot),一般取中间位置;2.将原序列分为<=pivot,pivot,>=pivot的样子;3.递归进行以上的操作。
注意:在开始位置>=结束位置时,要停止操作。
归并排序解法:
public class Solution { /** * @param A an integer array * @return void */ public void sortIntegers2(int[] A) { // Write your code here if (A == null || A.length == 0) { return; } int[] temp = new int[A.length]; mergeSort(A, 0, A.length - 1, temp); } private void mergeSort(int[] A, int start, int end, int[] temp) { if (start >= end) { return; } int mid = start + (end - start) / 2; mergeSort(A, start, mid, temp); mergeSort(A, mid + 1, end, temp); merge(A, start, mid, end, temp); } private void merge(int[] A, int start, int mid, int end, int[] temp) { int left = start; int right = mid + 1; int index = start; while (left <= mid && right <= end) { if (A[left] < A[right]) { temp[index++] = A[left++]; } else { temp[index++] = A[right++]; } } while (left <= mid) { temp[index++] = A[left++]; } while (right <= end) { temp[index++] = A[right++]; } for (int i = start; i <= end; i++) { A[i] = temp[i]; } } }
思想:分治,先局部有序再整体有序。将两个已经排序的序列合并成一个序列。
注意:在开始位置>=结束位置时,要停止操作。
30.sort-integers(整数排序)
给一组整数,按照升序排序,使用选择排序,冒泡排序,插入排序或者任何 O(n2) 的排序算法。
冒泡排序解法:
public class Solution { /** * @param A an integer array * @return void */ public void sortIntegers(int[] A) { // Write your code here int n = A.length; for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - 1 - i; j++) { if (A[j] > A[j + 1]) { int temp = A[j]; A[j] = A[j + 1]; A[j + 1] = temp; } } } } }
选择排序解法:
public class Solution { /** * @param A an integer array * @return void */ public void sortIntegers(int[] A) { // Write your code here int n = A.length; int min; for (int i = 0; i < n - 1; i++) { min = i; for (int j = i + 1; j < n; j++) { if (A[j] < A[min]) { min = j; } } if (min != i) { int temp = A[min]; A[min] = A[i]; A[i] = temp; } } } }
插入排序解法:
public class Solution { /** * @param A an integer array * @return void */ public void sortIntegers(int[] A) { // Write your code here int n = A.length; for (int i = 1; i < n; i++) { int temp = A[i]; int j = i - 1; while (j >= 0 && A[j] > temp) { A[j + 1] = A[j]; j--; } A[j + 1] = temp; } } }