一颗树,要么是空树,要么有两个指针,每个指针指向一棵树.树是一种递归结构,很多树的问题可以使用递归来解决!
二叉树的中序遍历
难度级别: 中等
递归实现
public static List<Integer> res;
public List<Integer> inorderTraversal(TreeNode root) {
res = new ArrayList<>();
inOrderTraversal(root);
return res;
}
private void inOrderTraversal(TreeNode root) {
if (root == null) {
return;
}
inOrderTraversal(root.left);
res.add(root.val);
inOrderTraversal(root.right);
}
二叉树中序遍历非递归实现,数据结构:栈
public static List<Integer> res;
public List<Integer> inorderTraversal(TreeNode root) {
res = new ArrayList<>();
inOrderTraversal(root);
return res;
}
private void inOrderTraversal(TreeNode root) {
if (root == null) {
return;
}
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || root != null) {
if (root != null) {
stack.push(root);
root = root.left;
} else {
root = stack.pop();
res.add(root.val);
root = root.right;
}
}
System.out.println();
}
对称二叉树
难度级别: 简单
对称二叉树的递归实现
public boolean isSymmetric(TreeNode root) {
if (root == null) {
return true;
}
return isSymmetric(root.left, root.right);
}
private boolean isSymmetric(TreeNode t1, TreeNode t2) {
if (t1 == null && t2 == null) {
return true;
}
if (t1 == null || t2 == null) {
return false;
}
if (t1.val != t2.val) {
return false;
}
return isSymmetric(t1.left, t2.right) && isSymmetric(t1.right, t2.left);
}
对称二叉树的非递归实现,数据结构:队列(bfs)
public boolean isSymmetric(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
queue.add(root);
while (!queue.isEmpty()) {
TreeNode t1 = queue.poll();
TreeNode t2 = queue.poll();
if (t1 == null && t2 == null) {
continue;
}
if (t1 == null || t2 == null) {
return false;
}
if (t1.val != t2.val) {
return false;
}
queue.add(t1.left);
queue.add(t2.right);
queue.add(t1.right);
queue.add(t2.left);
}
return true;
}
两种实现方法的时间复杂度为: O(n),空间复杂度: O(n)
树的高度
难度级别: 简单
求二叉树的最大深度递归实现
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
return 1+ Math.max(maxDepth(root.left), maxDepth(root.right));
}
求二叉树最大深度的非递归实现,用栈来实现,其中用到了Pair<K,V>,键值对映射.在javafx.util.Pair包中,需要导入!
private int depth = 0;
public int maxDepth(TreeNode root) {
Queue<Pair<TreeNode, Integer>> stack = new LinkedList<>();
if (root != null) {
stack.add(new Pair<>(root, 1));
}
int depth = 0;
while (!stack.isEmpty()) {
Pair<TreeNode, Integer> current = stack.poll();
root = current.getKey();
int cur_depth = current.getValue();
if (root != null) {
depth = Math.max(depth, cur_depth);
stack.add(new Pair<>(root.left, cur_depth + 1));
stack.add(new Pair<>(root.right, cur_depth + 1));
}
}
return depth;
}
平衡二叉树
难度级别: 简单
3
/ \
9 20
/ \
15 7
true
1
/ \
2 2
/ \
3 3
/ \
4 4
false
平衡树左右子树的高度差的绝对值不超过1,即小于等于1
private boolean res = true;
public boolean isBalanced(TreeNode root) {
maxDepth(root);
return res;
}
private int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
int left = maxDepth(root.left);
int right = maxDepth(root.right);
if (Math.abs((left - right)) > 1) {
res = false;
}
return 1 + Math.max(left, right);
}
平衡二叉树
难度级别: 简单
平衡二叉树: 平衡树的左右子树的高度差的绝对值小于等于1
平衡二叉树的递归实现
private boolean res = true;
public boolean isBalanced(TreeNode root) {
maxDepth(root);
return res;
}
private int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
int left = maxDepth(root.left);
int right = maxDepth(root.right);
if (Math.abs((left - right)) > 1) {
res = false;
}
return 1 + Math.max(left, right);
}
求二叉树的最小深度
二叉树的最小深度递归实现
难度级别: 简单
写法一
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
int left = minDepth(root.left);
int right = minDepth(root.right);
if (left == 0 || right == 0) {
return left + right + 1;
}
return Math.min(left, right) + 1;
}
写法二
public int minDepth(TreeNode root) {
return dfs(root);
}
private int dfs(TreeNode root) {
if (root == null) {
return 0;
}
//若不考虑以下两种情况,leetcode测试用例只能过去一部分
if (root.left == null) {
return 1 + minDepth(root.right);
}
if (root.right == null) {
return 1 + minDepth(root.left);
}
return 1 + Math.min(dfs(root.left), dfs(root.right));
}
时间复杂度:O(n) ,n为节点的个数; 空间复杂度:O(n)
路径的和
leetcode112.路径的和(判断是否存在路径和等于一个数)
难度级别: 简单
路径总和递归实现
public boolean hasPathSum(TreeNode root, int sum) {
if (root == null) {
return false;
}
if (root.left == null && root.right == null && root.val == sum) {
return true;
}
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
二叉树的前序遍历
难度级别: 中等
递归实现
static List<Integer> res;
public List<Integer> preorderTraversal(TreeNode root) {
res = new ArrayList<>();
preOrderTraversal(root);
return res;
}
private void preOrderTraversal(TreeNode root) {
if (root == null) {
return;
}
res.add(root.val);
preOrderTraversal(root.left);
preOrderTraversal(root.right);
}
非递归实现,数据结构:栈
static List<Integer> res;
public List<Integer> preorderTraversal(TreeNode root) {
res = new ArrayList<>();
preOrderTravsersal(root);
return res;
}
private void preOrderTravsersal(TreeNode root) {
if (root == null) {
return;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
root = stack.pop();
res.add(root.val);
if (root.right != null) {
stack.push(root.right);
}
if (root.left != null) {
stack.push(root.left);
}
}
System.out.println();
}
翻转二叉树
难度级别:简单
递归实现
public TreeNode invertTree(TreeNode root) {
if (root==null){
return null;
}
TreeNode left = root.left;
root.left = invertTree(root.right);
root.right =invertTree(left);
return root;
}
打家劫舍III
难度级别: 中等
递归实现
public int rob(TreeNode root) {
if (root == null) {
return 0;
}
int val1 = root.val;
if (root.left != null) {
val1 += rob(root.left.left) + rob(root.left.right);
}
if (root.right != null) {
val1 += rob(root.right.left) + rob(root.right.right);
}
int val2 = rob(root.left) + rob(root.right);
return Math.max(val1, val2);
}
左叶子之和
leetcode404.左叶子之和(即求左子树叶子节点的和)
难度级别: 简单
递归实现
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) {
return 0;
}
if (isLeaf(root.left)) {
return root.left.val + sumOfLeftLeaves(root.right);
}
return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
}
private boolean isLeaf(TreeNode root) {
if (root == null) {
return false;
}
return root.left == null && root.right == null;
}
路径总和
leetcode437.路径总和(即找出路径和等于给定数值的路径总数)
难度级别: 简单
递归实现
public int pathSum(TreeNode root, int sum) {
if (root == null) {
return 0;
}
int res = pathSumWithRoot(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);
return res;
}
private int pathSumWithRoot(TreeNode root, int sum) {
if (root == null) {
return 0;
}
int res = 0;
if (root.val == sum) {
res++;
}
res += pathSumWithRoot(root.left, sum - root.val) + pathSumWithRoot(root.right, sum - root.val);
return res;
}
二叉树的直径
难度级别: 简单
递归实现
private int max = 0;
public int diameterOfBinaryTree(TreeNode root) {
maxDepth(root);
return max;
}
private int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
int leftDepth = maxDepth(root.left);
int rightDepth = maxDepth(root.right);
max = Math.max(max, (leftDepth + rightDepth));
return Math.max(leftDepth, rightDepth) + 1;
}
另一个树的子树
leetcode572.另一个树的子树(即在一个树中找另个一个树 )
难度级别: 简单
递归实现
public boolean isSubtree(TreeNode s, TreeNode t) {
if (s == null) {
return false;
}
if (t == null) {
return false;
}
return isSubtreeWithRoot(s, t) || isSubtree(s.left, t) || isSubtree(s.right, t);
}
private boolean isSubtreeWithRoot(TreeNode s, TreeNode t) {
if (s == null && t == null) {
return true;
}
if (s == null || t == null) {
return false;
}
if (t.val != s.val) {
return false;
}
return isSubtreeWithRoot(s.left, t.left) && isSubtreeWithRoot(s.right, t.right);
}
合并两个二叉树
难度级别: 简单
递归实现
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
return mergeTwoTrees(t1, t2);
}
private TreeNode mergeTwoTrees(TreeNode t1, TreeNode t2) {
if (t1 == null && t2 == null) {
return null;
}
if (t1 == null && t2 != null) {
return t2;
}
if (t1 != null && t2 == null) {
return t1;
}
TreeNode root = new TreeNode((t1.val + t2.val));
root.left = mergeTwoTrees(t1.left, t2.left);
root.right = mergeTwoTrees(t1.right, t2.right);
return root;
}
求二叉树中的第二小的节点
难度级别: 简单
递归实现
public int findSecondMinimumValue(TreeNode root) {
if (root == null) {
return -1;
}
if (root.left == null && root.right == null) {
return -1;
}
int leftVal = root.left.val;
int rightVal = root.right.val;
if (leftVal == root.val) {
leftVal = findSecondMinimumValue(root.left);
}
if (rightVal == root.val) {
rightVal = findSecondMinimumValue(root.right);
}
if (leftVal != -1 && rightVal != -1) {//左右节点都有第二最小值,求最小值
return Math.min(leftVal, rightVal);
}
if (leftVal != -1) {//只有左边有,否则返回右边
return leftVal;
}
return rightVal;
}
最长同值路径
难度级别: 简单
递归实现
private int path = 0;
public int longestUnivaluePath(TreeNode root) {
dfs(root);
return path;
}
private int dfs(TreeNode root) {
if (root == null) {
return 0;
}
int left = dfs(root.left);
int right = dfs(root.right);
int leftPath = root.left != null && root.left.val == root.val ? left + 1 : 0;
int rightPath = root.right != null && root.right.val == root.val ? right + 1 : 0;
path = Math.max(path, (leftPath + rightPath));
return Math.max(leftPath, rightPath);
}
使用 BFS 进行层次遍历。不需要使用两个队列来分别存储当前层的节点和下一层的节点,因为在开始遍历一层的节点时,当前队列中的节点数就是当前层的节点数,只要控制遍历这么多节点数,就能保证这次遍历的都是当前层的节点。
一棵树每层节点的平均数