目录
1.binary-tree-preorder-traversal
2.binary-tree-postorder-traversal
3.binary-tree-inorder-traversal
4.binary-tree-level-order-traversal
5.binary-tree-zigzag-level-order-traversal
6.binary-tree-level-order-traversal-ii
7.construct-binary-tree-from-preorder-and-inorder-traversal
8.construct-binary-tree-from-inorder-and-postorder-traversal
9. Minimum Depth of Binary Tree
10.maximum-depth-of-binary-tree
15.binary-tree-maximum-path-sum
18.populating-next-right-pointers-in-each-node
19.populating-next-right-pointers-in-each-node-ii
21.unique-binary-search-trees-ii
23.validate-binary-search-tree
1.binary-tree-preorder-traversal
题目:求给定二叉树的前序遍历
分析:迭代实现,前序遍历根结点,先后将右、左子树压入栈,这样的访问顺序为“中左右”,即前序遍历。
public ArrayList<Integer> preorderTraversal(TreeNode root) {
ArrayList<Integer> list = new ArrayList<>();
if(root == null)
return list;
Stack<TreeNode> stack = new Stack();
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);
list.add(node.val);
}
return list;
}
2.binary-tree-postorder-traversal
题目:求给定二叉树的后序遍历
分析:迭代实现,前序遍历根结点,先后将左右子树压入栈,这样的访问顺序为“中右左”,最后再reverse即可。reverse: list.add(0,node.val);
public ArrayList<Integer> postorderTraversal(TreeNode root) {
ArrayList<Integer> list = new ArrayList();
if(root == null)
return list;
Stack<TreeNode> s = new Stack();
s.push(root);
while(!s.empty()){
TreeNode node = s.pop();
if(node.left != null)
s.push(node.left);
if(node.right != null)
s.push(node.right);
list.add(0,node.val);//因为出栈顺序为“根右左”,所以需要每次将元素插入list开头
}
return list;
}
3.binary-tree-inorder-traversal
题目:给出一棵二叉树,返回这棵树的中序遍历。例如:给出的二叉树为{1,#,2,3},返回[1,3,2].
分析:用栈来实现二叉树的中序遍历
public ArrayList<Integer> inorderTraversal(TreeNode root) {
ArrayList<Integer> list = new ArrayList();
if(root == null)
return list;
Stack<TreeNode> stack = new Stack();
TreeNode cur = root;
while(! stack.empty() || cur != null){
if(cur != null){
stack.push(cur);
cur = cur.left;
}
else{
cur = stack.pop();
list.add(cur.val);
cur = cur.right;
}
}
return list;
}
4.binary-tree-level-order-traversal
题目:给定一个二叉树,返回该二叉树层序遍历的结果。例如:给定的二叉树{3,9,20,#,#,15,7},该二叉树层序遍历的结果是[↵ [3],↵ [9,20],↵ [15,7]↵]
分析:见剑指offer面试题32-1https://blog.csdn.net/Nibaby9/article/details/104124413
5.binary-tree-zigzag-level-order-traversal
题目:给定一个二叉树,返回该二叉树的之字形层序遍历,(从左向右,下一层从右向左,一直这样交替)。例如:给定的二叉树{3,9,20,#,#,15,7}, 该二叉树之字形层序遍历的结果是[↵ [3],↵ [20,9],↵ [15,7]↵]
分析:见剑指offer面试题32-2https://blog.csdn.net/Nibaby9/article/details/104124413
6.binary-tree-level-order-traversal-ii
题目:给定一个二叉树,返回该二叉树由底层到顶层的层序遍历,(从左向右,从叶子节点到根节点,一层一层的遍历)例如:给定的二叉树是{3,9,20,#,#,15,7},该二叉树由底层到顶层层序遍历的结果是[↵ [15,7]↵ [9,20],↵ [3],↵]
分析:还是按原来的方法进行层序遍历,只不过把每层遍历的结果都加到结果集的最前面。
public ArrayList<ArrayList<Integer>> levelOrderBottom(TreeNode root) {
ArrayList<ArrayList<Integer>> result = new ArrayList();
if(root == null)
return result;
ArrayList<Integer> list = new ArrayList();
LinkedList<TreeNode> queue = new LinkedList();
queue.offer(root);
while(! queue.isEmpty()){
list.clear();
int size = queue.size();
while(size > 0){
TreeNode cur = queue.poll();
size--;
list.add(cur.val);
if(cur.left != null)
queue.offer(cur.left);
if(cur.right != null)
queue.offer(cur.right);
}
result.add(0,new ArrayList(list));
}
return result;
}
7.construct-binary-tree-from-preorder-and-inorder-traversal
题目:给出一棵树的前序遍历和中序遍历,请构造这颗二叉树。注意:可以假设树中不存在重复的节点
分析:见剑指offer面试题7https://blog.csdn.net/Nibaby9/article/details/104124413
8.construct-binary-tree-from-inorder-and-postorder-traversal
题目:给出一棵树的中序遍历和后序遍历,请构造这颗二叉树。注意:保证给出的树中不存在重复的节点
分析:同中序遍历和先序遍历的构造!!
public TreeNode buildTree(int[] inorder, int[] postorder) {
if(inorder == null || postorder == null || inorder.length != postorder.length || inorder.length == 0)
return null;
return build(inorder,postorder,0,inorder.length-1,0,postorder.length-1);
}
private TreeNode build(int[] inorder, int[] postorder, int instart, int inend,int pstart, int pend) {
if(instart > inend || pstart > pend)
return null;
TreeNode root = new TreeNode(postorder[pend]);
int size = 0;
for(int i = instart;i <= inend;i++){
if(postorder[pend] == inorder[i])
break;
size++;
}
root.left = build(inorder,postorder,instart,instart+size-1,pstart,pstart+size-1);
root.right = build(inorder,postorder,instart+size+1,inend,pstart+size,pend-1);
return root;
}
9. Minimum Depth of Binary Tree
题目:求给定二叉树的最小深度。最小深度是指树的根结点到最近叶子结点的最短路径上结点的数量。
分析:递归实现,注意分析没有左子树和右子树的情况 f(x) = 1 + min{ f(left),f(right) }
public int run(TreeNode root) {
if(root == null){
return 0;
}
int left = run(root.left);
int right = run(root.right);
if(left == 0 || right == 0)
return left + right + 1;
return 1 + (left > right ? right :left);
}
10.maximum-depth-of-binary-tree
题目:求给定二叉树的最大深度,最大深度是指树的根结点到最远叶子结点的最长路径上结点的数量。
分析:见剑指offer面试题55https://blog.csdn.net/Nibaby9/article/details/104124413
11.balanced-binary-tree
题目:判断给定的二叉树是否是平衡的。
分析:见剑指offer面试题55拓展https://blog.csdn.net/Nibaby9/article/details/104124413
12.sum-root-to-leaf-numbers
题目:给定一个仅包含数字0-9的二叉树,每一条从根节点到叶子节点的路径都可以用一个数字表示。例如根节点到叶子节点的一条路径是1->2->3,那么这条路径就用123来代替。找出根节点到叶子节点的所有路径表示的数字之和。例如: 1↵ / ↵ 2 3;根节点到叶子节点的路径1->2用数字12代替,根节点到叶子节点的路径1->3用数字13代替,所以答案为12+13=25。
分析:主要在于参数的设计,记根结点以上的和为sum = sum*10+root.val;最后结果为左子树的和加右子树的和。
public int sumNumbers(TreeNode root) {
return sumUtil(root,0);
}
private int sumUtil(TreeNode root,int sum) {
if(root == null)
return 0;
sum = sum * 10 + root.val;
if(root.left == null && root.right == null)
return sum;
return sumUtil(root.left,sum) + sumUtil(root.right,sum);
}
13.path-sum
题目:给定一个二叉树和一个值sum,判断是否有从根节点到叶子节点的节点值之和等于sum的路径
分析:递归求解,hasPathSum(root.left,sum - root.val) || hasPathSum(root.right,sum - root.val)
public boolean hasPathSum(TreeNode root, int sum) {
if(root == null)
return false;
if(root.left == null && root.right == null && root.val == sum)
return true;
if(root.left != null && hasPathSum(root.left,sum - root.val))
return true;
if(root.right != null && hasPathSum(root.right,sum - root.val))
return true;
return false;
}
14.path-sum-ii
题目:给定一个二叉树和一个值sum,请找出所有的根节点到叶子节点的节点值之和等于sum的路径
例如:给出如下的二叉树,sum=22, 5↵ / ↵ 4 8↵ / / ↵ 11 13 4↵ / / ↵ 7 2 5 1,返回[↵ [5,4,11,2],↵ [5,8,4,5]↵]↵
分析:递归求解,主要还是在于参数的设置
public ArrayList<ArrayList<Integer>> pathSum(TreeNode root, int sum) {
ArrayList<ArrayList<Integer>> result = new ArrayList();
if(root == null)
return result;
ArrayList<Integer> tmp = new ArrayList();
pathSumUtil(root,sum,result,tmp);
return result;
}
private void pathSumUtil(TreeNode root, int sum, ArrayList<ArrayList<Integer>> result, ArrayList<Integer> tmp) {
tmp.add(root.val);//试探
if(root.val == sum && root.left == null && root.right == null)
result.add(new ArrayList(tmp));
if(root.left != null)
pathSumUtil(root.left,sum - root.val,result,tmp);
if(root.right != null)
pathSumUtil(root.right,sum - root.val,result,tmp);
tmp.remove(tmp.size() - 1);//回溯!!!
}
15.binary-tree-maximum-path-sum
题目:给定一个二叉树,请计算节点值之和最大的路径的节点值之和是多少。这个路径的开始节点和结束节点可以是二叉树中的任意节点。例如:给出以下的二叉树, 1↵ / ↵ 2 3,返回的结果为6
分析:需计算两个最大值,一个是当前节点下最大路径和,另一个是如果要连接父节点时最大的路径和。用前者更新全局最大量,用后者返回递归值就行了。
public class Solution {
int max = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
sumUtil(root);
return max;
}
private int sumUtil(TreeNode root) {
if(root == null)
return 0;
int left = Math.max(0, sumUtil(root.left));
int right = Math.max(0, sumUtil(root.right));
max = Math.max(max, root.val + left + right);
return Math.max(left, right) + root.val;
}
}
16.symmetric-tree
题目:给定一棵二叉树,判断琪是否是自身的镜像(即:是否对称)
分析:见剑指offer面试题28https://blog.csdn.net/Nibaby9/article/details/104124413
17.same-tree
题目:给出两个二叉树,请写出一个判断两个二叉树是否相等的函数。判断两个二叉树相等的条件是:两个二叉树的结构相同,并且相同的节点上具有相同的值。
分析:easy!递归判断左右子树是否相同即可。
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q == null)
return true;
if(p == null || q == null)
return false;
if(p.val != q.val)
return false;
return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}
18.populating-next-right-pointers-in-each-node
题目:给定一棵满二叉树 struct TreeLinkNode {TreeLinkNode *left;TreeLinkNode *right;TreeLinkNode *next; }填充所有节点的next指针,指向它右兄弟节点。如果没有右兄弟节点,则应该将next指针设置为NULL。初始时,所有的next指针都为NULL
分析:由于给定的树为满二叉树,所以对于一个结点:它的左子树的next为它的右子树;它的右子树的next为它的next的左子树
public void connect(TreeLinkNode root) {
if(root == null)
return;
if(root.left != null && root.right != null)
root.left.next = root.right;
if(root.next != null && root.right != null)
root.right.next = root.next.left;
connect(root.left);
connect(root.right);
}
19.populating-next-right-pointers-in-each-node-ii
题目:继续思考"Populating Next Right Pointers in Each Node".这道题。如果给定的树可以是任意的二叉树呢?你之前的给出的算法还有效吗?注意:你只能使用常量的额外内存空间
分析:层次遍历,但遍历前先模拟新建立的每层的第一个结点,以方便后面遍历
public void connect(TreeLinkNode root) {
while(root != null){
TreeLinkNode firstNode = new TreeLinkNode(0);
TreeLinkNode cur = firstNode;
while(root != null){
if(root.left != null){
cur.next = root.left;
cur = cur.next;
}
if(root.right != null){
cur.next = root.right;
cur = cur.next;
}
root = root.next;
}
root = firstNode.next;
}
}
20.unique-binary-search-trees
题目:给定一个值n,能构建出多少不同的值包含1...n的二叉搜索树(BST)?例如:给定 n = 3, 有五种不同的二叉搜索树
分析:动态规划。一维数组dp[i]表示1...i数字能组成多少种二叉搜索树,dp[0] = 1;dp[1] = 1;dp[n] = sum{dp[j] * dp[n-j-1]},0<j<n
public int numTrees(int n) {
if(n < 0)
return 0;
int []dp = new int[n+1];
dp[0] = 1;
dp[1] = 1;
for(int i = 2;i <= n;i++){
for(int j =0;j < i;j++){
dp[i] += dp[j] * dp[i-j-1];
}
}
return dp[n];
}
21.unique-binary-search-trees-ii
题目:给定一个值n,请生成所有的存储值1...n.的二叉搜索树(BST)的结构例如:给定n=3,你的程序应该给出五种不同的二叉搜索树
分析:用递归求出以i为根结点的所有左子树和右子树,然后再将所有左子树和右子树相互配对。
public ArrayList<TreeNode> generateTrees(int n) {
return generateTreesUtil(1,n);
}
private ArrayList<TreeNode> generateTreesUtil(int low, int high) {
ArrayList<TreeNode> result = new ArrayList();
if (low > high) {
result.add(null);
return result;
}
for(int i = low;i <= high;i++){//以i为根结点生成树
ArrayList<TreeNode> left = generateTreesUtil(low,i-1);
ArrayList<TreeNode> right = generateTreesUtil(i+1,high);
for(int j = 0;j < left.size();j++){
for(int k = 0;k < right.size();j++){
TreeNode root = new TreeNode(i);
root.left = left.get(j);
root.right = right.get(k);
result.add(root);
}
}
}
return result;
}
22.recover-binary-search-tree
题目:二叉搜索树(BST)中的两个节点被错误地交换了,请在不改变树的结构的情况下恢复这棵树。备注:用O(n)的空间解决这个问题的方法太暴力了,你能设计一个常数级空间复杂度的算法么?
分析:利用二叉搜索树中序遍历有序性,对于一组有序的数,两个数被错误调换,如1 2 10 8 9 4 11 12,第一个错误数是第一次出现pre>cur中的pre,第二个错误数是最后一次出现pre>cur中的cur.
public void recoverTree(TreeNode root) {
TreeNode first = null;
TreeNode second = null;
TreeNode pre = null;
if(root == null)
return;
Stack<TreeNode> s = new Stack();
TreeNode cur = root;
while(!s.empty() || cur != null){
if(cur != null){
s.push(cur);
cur = cur.left;
}
else{
cur = s.pop();
if(pre != null){
if(pre.val > cur.val) {
if (first == null)
first = pre;
second = cur;
}
}
pre = cur;
cur = cur.right;
}
}
if(first != null && second != null){
int temp = first.val;
first.val = second.val;
second.val = temp;
}
}
23.validate-binary-search-tree
题目:判断给出的二叉树是否是一个二叉搜索树(BST)
分析:利用二叉搜索树中序遍历有序性,注意二叉搜索树满足左子树 < 根结点 < 右子树,没有等号,[1,1]不是BST
public boolean isValidBST(TreeNode root) {
if(root == null)
return true;
TreeNode pre = null;
Stack<TreeNode> s = new Stack();
TreeNode cur = root;
while(!s.empty() || cur != null){
if(cur != null){
s.push(cur);
cur = cur.left;
}
else{
cur = s.pop();
if(pre != null){
if(pre.val >= cur.val)
return false;
}
pre = cur;
cur = cur.right;
}
}
return true;
}