处理二叉树问题的神器是递归。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
二叉树的遍历
144 Binary Tree Preorder Traversal Medium
Given a binary tree, return the preorder traversal of its nodes' values.
Example:
Input: [1,null,2,3]
1
\
2
/
3
Output: [1,2,3]
Follow up: Recursive solution is trivial, could you do it iteratively?
经典题:二叉树前序遍历的非递归实现(栈)
伪代码:
1. 栈初始化
2. 循环直到root为空且栈为空
2.1 当root非空时循环
2.1.1 输出root.val
2.1.2 将root入栈
2.1.3 继续遍历root的左子树
2.2 如果栈非空,则
2.2.1 栈顶元素弹出至root
2.2.2 准备遍历root的右子树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Deque<TreeNode> stack = new ArrayDeque<>();
while(root!=null || stack.size()!=0) {
while(root!=null) {
result.add(root.val);
stack.addFirst(root);
root = root.left;
}
if(stack.size()!=0) {
root = stack.removeFirst();
root = root.right;
}
}
return result;
}
}
94 Binary Tree Inorder Traversal Medium
Given a binary tree, return the inorder traversal of its nodes' values.
Example:
Input: [1,null,2,3]
1
\
2
/
3
Output: [1,3,2]
Follow up: Recursive solution is trivial, could you do it iteratively?
经典题:二叉树中序遍历的非递归实现(栈)
伪代码:
1. 栈初始化
2. 循环直到root为空且栈为空
2.1 当root非空时循环
2.1.1 将root入栈
2.1.2 继续遍历root的左子树
2.2 如果栈非空,则
2.2.1 栈顶元素弹出至root
2.2.2 输出root.val
2.2.3 准备遍历root的右子树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Deque<TreeNode> stack = new ArrayDeque<>();
while(root!=null || stack.size()!=0) {
while(root!=null) {
stack.addFirst(root);
root = root.left;
}
if(stack.size()!=0) {
root = stack.removeFirst();
result.add(root.val);
root = root.right;
}
}
return result;
}
}
145 Binary Tree Postorder Traversal Hard
Given a binary tree, return the postorder traversal of its nodes' values.
Example:
Input: [1,null,2,3]
1
\
2
/
3
Output: [3,2,1]
Follow up: Recursive solution is trivial, could you do it iteratively?
经典题:二叉树后序遍历的非递归实现(栈)
与前序遍历和中序遍历不同,结点需要入栈两次、出栈两次。为了区别同一个结点的两次出栈,设置标志flag:
flag=1 第一次出栈,只遍历完左子树,该结点不能访问
flag=2 第二次出栈,遍历完右子树,该结点可以访问
伪代码:
1. 栈初始化
2. 循环直到root为空且栈为空
2.1 当root非空时循环
2.1.1 将root连同标志flag=1入栈
2.1.2 继续遍历root的左子树
2.2 当栈非空 且 栈顶元素flag=2时循环
2.2.1 栈顶元素弹出至root
2.2.2 输出root.val
2.2.3 root置为空
2.3 如果栈非空,则
2.2.1 栈顶元素的标志flag改为2
2.2.2 准备遍历栈顶结点的右子树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Deque<TreeNode> stack = new ArrayDeque<>();
Deque<Integer> flag = new ArrayDeque<>();
while(root!=null || stack.size()!=0) {
while(root!=null) {
stack.addFirst(root);
flag.addFirst(1);
root = root.left;
}
while(stack.size()!=0 && flag.peekFirst()==2) {
root = stack.removeFirst();
flag.removeFirst();
result.add(root.val);
root = null; //重要!否则程序陷入死循环,永远跳不出外层while循环
}
if(stack.size()!=0) {
flag.removeFirst();
flag.addFirst(2);
root = stack.peekFirst().right;
}
}
return result;
}
}
102 Binary Tree Level Order Traversal Medium
Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).
For example:
Given binary tree [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
return its level order traversal as:
[
[3],
[9,20],
[15,7]
]
经典题:二叉树层次遍历(队列)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
LinkedList<TreeNode> queue = new LinkedList<>();
if(root != null) {
queue.add(root);
}
while(queue.size()!=0) {
int count = queue.size();
List<Integer> level = new ArrayList<>();
for(int i=0; i<count; i++) { // 关键
TreeNode node = queue.remove();
level.add(node.val);
if(node.left!=null) {
queue.add(node.left);
}
if(node.right!=null) {
queue.add(node.right);
}
}
result.add(level);
}
return result;
}
}
103 Binary Tree Zigzag Level Order Traversal Medium
Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).
For example:
Given binary tree [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
return its zigzag level order traversal as:
[
[3],
[20,9],
[15,7]
]
题意:二叉树的之字形层次遍历(两个栈)
注意:打印偶数层时,先放入右结点,再放入左结点。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
Deque<TreeNode> stack1 = new ArrayDeque<>();
Deque<TreeNode> stack2 = new ArrayDeque<>();
if(root != null) {
stack1.add(root);
}
int level_count = 0;
while(!stack1.isEmpty() || !stack2.isEmpty()) {
level_count++;
List<Integer> level = new ArrayList<>();
TreeNode node = null;
if(level_count%2 != 0) {
// 正向
while(!stack1.isEmpty()) {
node = stack1.removeFirst();
level.add(node.val);
if(node.left!=null) {
stack2.addFirst(node.left);
}
if(node.right!=null) {
stack2.addFirst(node.right);
}
}
} else {
// 反向
while(!stack2.isEmpty()) {
node = stack2.removeFirst();
level.add(node.val);
if(node.right!=null) {
stack1.addFirst(node.right);
}
if(node.left!=null) {
stack1.addFirst(node.left);
}
}
}
result.add(level);
}
return result;
}
}
二叉树的构建
105 Construct Binary Tree from Preorder and Inorder Traversal Medium
Given preorder and inorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
For example, given
preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]
Return the following binary tree:
3
/ \
9 20
/ \
15 7
经典题:由前序遍历&中序遍历序列构造二叉树
前序遍历中,第一个结点一定是二叉树的根结点;
中序遍历中,根结点必然将中序序列分割成两个子序列,前一个子序列是根结点左子树的中序序列,后一个子序列是根 结点右子树的中序序列。根据这两个子序列,在前序遍历序列中找到对应的左子序列和右子序列。递归……
例子:
前序:3 9 | 20 15 7
中序:9 3 | 15 20 7
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length == 0) {
return null;
}
TreeNode root = new TreeNode(preorder[0]);
int loc = getIndex(inorder, preorder[0]); // 根结点在中序序列中的下标
int left_length = loc; // 左子序列长度
int right_length = inorder.length-1-loc; // 右子序列长度
if(left_length>0) { // 如果不做判断,可能会导致下标越界
root.left = buildTree(Arrays.copyOfRange(preorder,1,1+left_length), Arrays.copyOfRange(inorder,0,left_length));
}
if(right_length>0) {
root.right = buildTree(Arrays.copyOfRange(preorder,1+left_length,preorder.length), Arrays.copyOfRange(inorder,1+left_length,preorder.length));
}
return root;
}
private int getIndex(int[] a, int num) {
for(int i=0; i<a.length; i++) {
if(a[i] == num) {
return i;
}
}
return -1;
}
}
106 Construct Binary Tree from Inorder and Postorder Traversal Medium
Given inorder and postorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
For example, given
inorder = [9,3,15,20,7]
postorder = [9,15,7,20,3]
Return the following binary tree:
3
/ \
9 20
/ \
15 7
经典题:由中序遍历&后序遍历序列构造二叉树
后序遍历中,最后一个结点一定是二叉树的根结点;
中序遍历中,根结点必然将中序序列分割成两个子序列,前一个子序列是根结点左子树的中序序列,后一个子序列是根 结点右子树的中序序列。根据这两个子序列,在后序遍历序列中找到对应的左子序列和右子序列。递归……
例子:
前序:9 3 | 15 20 7
中序:9 | 15 7 20 3
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if(inorder.length == 0) {
return null;
}
TreeNode root = new TreeNode(postorder[postorder.length-1]);
int loc = getIndex(inorder, postorder[postorder.length-1]); // 根结点在中序序列中的下标
int left_length = loc; // 左子序列长度
int right_length = inorder.length-1-loc; // 右子序列长度
if(left_length>0) {
root.left = buildTree(Arrays.copyOfRange(inorder, 0, left_length), Arrays.copyOfRange(postorder, 0, left_length));
}
if(right_length>0) {
root.right = buildTree(Arrays.copyOfRange(inorder, loc+1, inorder.length), Arrays.copyOfRange(postorder, left_length, postorder.length-1));
}
return root;
}
private int getIndex(int[] a, int num) {
for(int i=0; i<a.length; i++) {
if(a[i] == num) {
return i;
}
}
return -1;
}
}
二叉查找树(二叉搜索树)
二叉查找树,也称二叉搜索树、有序二叉树、排序二叉树,是指一棵空树或者具有下列性质的二叉树:
若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
任意节点的左、右子树也分别为二叉查找树;
没有键值相等的节点。
98 Validate Binary Search Tree Medium
Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
The left subtree of a node contains only nodes with keys less than the node's key.
The right subtree of a node contains only nodes with keys greater than the node's key.
Both the left and right subtrees must also be binary search trees.
Example 1:
Input:
2
/ \
1 3
Output: true
Example 2:
5
/ \
1 4
/ \
3 6
Output: false
Explanation: The input is: [5,1,4,null,null,3,6]. The root node's value
is 5 but its right child's value is 4.
经典题:判断是否为二叉查找树BST
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
private boolean isValidBST(TreeNode root, long min, long max) {
if(root == null) {
return true;
}
if(root.val<=min || root.val>=max) {
return false;
}
return isValidBST(root.left, min, root.val) && isValidBST(root.right, root.val, max);
}
}
108 Convert Sorted Array to Binary Search Tree Easy
Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
Example:
Given the sorted array: [-10,-3,0,5,9],
One possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST:
0
/ \
-3 9
/ /
-10 5
思路:二分法+递归
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return sortedArrayToBST(nums, 0, nums.length-1);
}
private TreeNode sortedArrayToBST(int[] nums, int low, int high) {
if(low>high) {
return null;
}
int mid = low + (high-low)/2;
TreeNode root = new TreeNode(nums[mid]);
root.left = sortedArrayToBST(nums, low, mid-1);
root.right = sortedArrayToBST(nums, mid+1, high);
return root;
}
}
二叉树的递归
104 Maximum Depth of Binary Tree Easy
Given a binary tree, find its maximum depth.
The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
Note: A leaf is a node with no children.
Example:
Given binary tree [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
return its depth = 3.
经典题:计算二叉树的最大深度
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) {
return 0;
}
return 1 + Math.max(maxDepth(root.left),maxDepth(root.right));
}
}
111 Minimum Depth of Binary Tree Easy
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
Note: A leaf is a node with no children.
Example:
Given binary tree [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
return its minimum depth = 2.
题意:计算二叉树的最小深度
注意:不能直接将上一题的Math.max改为Math.min,考虑下面一种情况:
1
/
2
对根结点来说,右子树不存在,就不能调用它的递归函数加入比较、计算。
上题因为是求最大值,加0不影响,这一题求最小值,如果不存在的子树以0加入计算,会算出不合法的深度。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int minDepth(TreeNode root) {
if(root == null) {
return 0;
}
if(root.left == null && root.right == null) {
return 1;
} else if(root.left == null) {
return 1 + minDepth(root.right);
} else if(root.right == null) {
return 1 + minDepth(root.left);
} else {
return 1 + Math.min(minDepth(root.left), minDepth(root.right));
}
}
}
112 Path Sum Easy
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
Example:
Given the below binary tree and sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if(root == null) {
return false;
}
if(root.left == null && root.right == null) { // 到叶子结点
return sum == root.val;
}
return hasPathSum(root.left, sum-root.val) || hasPathSum(root.right, sum-root.val);
}
}
230 Kth Smallest Element in a BST Medium
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.
Note:
You may assume k is always valid, 1 ≤ k ≤ BST's total elements.
Example 1:
Input: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
Output: 1
Example 2:
Input: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
Output: 3
Follow up:
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?
题意:求二叉搜索树的第k小的节点值
思路:中序遍历
递归代码中,即便找到了结果,还是要等到所有节点全部遍历结束后才return出来。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private int count = 0;
private int result;
public int kthSmallest(TreeNode root, int k) {
if(root.left != null) {
kthSmallest(root.left, k);
}
count++;
if(k == count) {
result = root.val;
}
if(root.right != null) {
kthSmallest(root.right, k);
}
return result;
}
}
其它
617 Merge Two Binary Trees Easy
Given two binary trees and imagine that when you put one of them to cover the other, some nodes of the two trees are overlapped while the others are not.
You need to merge them into a new binary tree. The merge rule is that if two nodes overlap, then sum node values up as the new value of the merged node. Otherwise, the NOT null node will be used as the node of new tree.
Example 1:
Input:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
Output:
Merged tree:
3
/ \
4 5
/ \ \
5 4 7
Note: The merging process must start from the root nodes of both trees.
题意:合并二叉树
思路:如果t1不存在,则直接返回t2,反之,如果t2不存在,则直接返回t1。如果上面两种情况都不满足,那么以t1和t2的结点值之和建立新结点t,然后对t1和t2的左子结点调用递归并赋给t的左子结点,再对t1和t2的右子结点调用递归并赋给t的右子结点,返回t结点即可。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
if(t1==null && t2==null) {
return null;
}
if(t1==null) {
return t2;
} else if(t2==null) {
return t1;
} else {
TreeNode t = new TreeNode(t1.val + t2.val);
t.left = mergeTrees(t1.left, t2.left);
t.right = mergeTrees(t1.right, t2.right);
return t;
}
}
}
669 Trim a Binary Search Tree Easy
Given a binary search tree and the lowest and highest boundaries as L and R, trim the tree so that all its elements lies in [L, R] (R >= L). You might need to change the root of the tree, so the result should return the new root of the trimmed binary search tree.
Example 1:
Input:
1
/ \
0 2
L = 1
R = 2
Output:
1
\
2
Example 2:
Input:
3
/ \
0 4
\
2
/
1
L = 1
R = 3
Output:
3
/
2
/
1
题意:修剪一棵二叉搜索树
思路:首先判断如果root为空,那么直接返回空即可。然后就是要看根结点是否在范围内,如果根结点值小于L,那么该结点=其右子结点(将其与其左子树删去),然后对该结点调用递归函数;同理,如果根结点大于R,那么该结点=其左子结点,然后对该结点调用递归函数。如果根结点在范围内,将其左子结点更新为对其左子结点调用递归函数的返回值,同样,将其右子结点更新为对其右子结点调用递归函数的返回值,最后返回root。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode trimBST(TreeNode root, int L, int R) {
if(root == null) {
return null;
}
if(root.val<L) {
root = root.right;
return trimBST(root, L, R);
} else if(root.val>R) {
root = root.left;
return trimBST(root, L, R);
} else {
root.left = trimBST(root.left, L, R);
root.right = trimBST(root.right, L, R);
return root;
}
}
}
637 Average of Levels in Binary Tree Easy
Given a non-empty binary tree, return the average value of the nodes on each level in the form of an array.
Example 1:
Input:
3
/ \
9 20
/ \
15 7
Output: [3, 14.5, 11]
Explanation:
The average value of nodes on level 0 is 3, on level 1 is 14.5, and on level 2 is 11. Hence return [3, 14.5, 11].
**Note:
The range of node's value is in the range of 32-bit signed integer.**
题意:计算二叉树的层平均值
我的思路:采用二叉树的层序遍历,用队列实现。层序遍历所有结点的值,相对于完全二叉树,若某个位置的结点不存在,以0记录,不影响求和。我们可以知道第一层1个结点,第二层2个结点,第三层4个结点,第四层8个结点…… 再对记录下的每层的数据求平均值。
这种方法有一个问题!这道题目结点的值可正、可负、可为0,因此将不存在的结点用0表示会出问题。
正确的方法:在层序遍历的过程中进行计算!
关键是,在将结点插入队列的过程中,如何知道哪些结点属于同一层呢?看代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> result = new ArrayList<>();
if(root == null) {
return result;
}
LinkedList<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(queue.size()!=0) {
// 关键:队列的一次循环就是一层
int count = queue.size();
long sum = 0; // 结点值为32位int,这里必须要用long,否则求和后有可能会超出int范围
for(int i=0; i<count; i++) {
TreeNode node = queue.remove();
sum += node.val;
// 队列中只放入有值的结点
if(node.left!=null) {
queue.add(node.left);
}
if(node.right!=null) {
queue.add(node.right);
}
}
result.add((double)sum/count);
}
return result;
}
}
226 Invert Binary Tree Easy
Invert a binary tree.
Example:
Input:
4
/ \
2 7
/ \ / \
1 3 6 9
Output:
4
/ \
7 2
/ \ / \
9 6 3 1
经典题:交换二叉树的左右子树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null) {
return null;
}
TreeNode temp = root.left; // 其实这里有一个疑问:下面root.left变了之后temp作为一个引用不是也应该变掉么,不知道怎么理解
root.left = invertTree(root.right);
root.right = invertTree(temp);
return root;
}
}