一、二叉树的相关概念
1、满二叉树
满二叉树:每一层都是满节点的状态。
深度为k的满二叉树一共有2^k-1个节点。
每层有2^(k-1)个节点。
2、完全二叉树
完全二叉树:除了最底层的节点没有填满外,其他的层的节点数都是达到了最大值。
3、二叉搜素树
二叉搜素树:某节点的左子树都是小于该节点值的,右子树都是大于该节点值的。
中序遍历之后是一个顺序数组。
4、平衡二叉搜索树
1⃣️是二叉搜索树
2⃣️左右子树的高度差的绝对值不超过1。
二、二叉树遍历方式
1、二叉树前序遍历
1.1 递归遍历
// 前序遍历
List<Integer> resList;
public List<Integer> preorderTraversal(TreeNode root) {
resList = new ArrayList<>();
preOrder(root);
return resList;
}
public void preOrder(TreeNode node) {
if (node == null) return;
resList.add(node.val);
preOrder(node.left);
preOrder(node.right);
}
1.2 迭代遍历
因为递归就是将一个一个函数押入栈中,所以可以通过栈来达到遍历的目的。
前序遍历的顺序是中左右,我们先把根节点压入栈中,然后弹出栈,将其右子节点和左子节点先后压入栈中,之所以是先压入右子节点再压入左子节点,是因为这样弹出的顺序就是左右了。
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
res.add(node.val);
if (node.right != null) stack.push(node.right);
if (node.left != null) stack.push(node.left);
}
return res;
}
2、二叉树中序遍历
2.1 递归遍历
// 中序遍历
List<Integer> resList;
public List<Integer> inorderTraversal(TreeNode root) {
resList = new ArrayList<>();
inOrder(root);
return resList;
}
public void inOrder(TreeNode node) {
if (node == null) return;
inOrder(node.left);
resList.add(node.val);
inOrder(node.right);
}
2.2 迭代遍历
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
if (cur != null) {
stack.push(cur);
cur = cur.left;
}else {
cur = stack.pop();
res.add(cur.val);
cur = cur.right;
}
}
return res;
}
3、二叉树后序遍历
3.1 递归遍历
// 后续遍历
List<Integer> resList;
public List<Integer> postorderTraversal(TreeNode root) {
resList = new ArrayList<>();
postOrder(root);
return resList;
}
public void postOrder(TreeNode node) {
if (node == null) return;
postOrder(node.left);
postOrder(node.right);
resList.add(node.val);
}
3.2 迭代遍历
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
res.add(node.val);
if (node.left != null) stack.push(node.left);
if (node.right != null) stack.push(node.right);
}
Collections.reverse(res);
return res;
}
4、二叉树层序遍历
4.1 递归遍历
List<List<Integer>> resList;
public List<List<Integer>> levelOrder(TreeNode root) {
resList = new ArrayList<>();
levelOrderUnit(root, 0);
return resList;
}
public void levelOrderUnit(TreeNode root, int deep) {
if (root == null) return;
deep++;
if (resList.size() < deep) {
List<Integer> list = new ArrayList<>();
resList.add(list);
}
resList.get(deep-1).add(root.val);
levelOrderUnit(root.left, deep);
levelOrderUnit(root.right, deep);
}
4.2 迭代遍历
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> resList = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
if (root == null) return resList;
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
List<Integer> list = new ArrayList<>();
while (size > 0) {
TreeNode node = queue.poll();
list.add(node.val);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
size--;
}
resList.add(list);
}
return resList;
}
三、二叉树的属性
1、对称二叉树
// 递归
public boolean isSymmetric(TreeNode root) {
return isSymmetricTree(root.left, root.right);
}
public boolean isSymmetricTree(TreeNode left, TreeNode right) {
if (left == null && right == null) return true;
if (left == null || right == null || left.val != right.val) return false;
return isSymmetricTree(left.left, right.right) && isSymmetricTree(left.right, right.left);
}
// 迭代
public boolean isSymmetric(TreeNode root) {
Deque<TreeNode> deque = new LinkedList<>();
deque.offerFirst(root.left);
deque.offerLast(root.right);
while (!deque.isEmpty()) {
TreeNode left = deque.pollFirst();
TreeNode right = deque.pollLast();
if (left == null && right == null ) continue;
if (left == null || right == null || left.val != right.val) return false;
deque.offerFirst(left.left);
deque.offerFirst(left.right);
deque.offerLast(right.right);
deque.offerLast(right.left);
}
return true;
}
2、二叉树的最大深度
// 递归
public int maxDepth(TreeNode root) {
if (root == null) return 0;
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
// 迭代
public int maxDepth(TreeNode root) {
int deep = 0;
if (root == null) return deep;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
deep++;
while (size > 0) {
TreeNode node = queue.poll();
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
size--;
}
}
return deep;
}
3、二叉树的最小深度
// 递归
public int minDepth(TreeNode root) {
if (root == null) return 0;
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
if (root.left == null) return rightDepth + 1;
if (root.right == null) return leftDepth + 1;
return Math.min(leftDepth, rightDepth) + 1;
}
// 迭代
public int minDepth(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
int depth = 0;
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
depth++;
while (size > 0) {
TreeNode node = queue.poll();
if (node.left == null && node.right == null) return depth;
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
size--;
}
}
return depth;
}
4、完全二叉树的节点个数
// 递归
public int countNodes(TreeNode root) {
if (root == null) return 0;
return countNodes(root.left) + countNodes(root.right) + 1;
}
// 迭代
public int countNodes(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> queue = new ArrayDeque<>();
int res = 0;
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
while (size > 0) {
TreeNode node = queue.poll();
res++;
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
size--;
}
}
return res;
}
// 完全二叉树解法
public int countNodes(TreeNode root) {
if (root == null) return 0;
int leftDepth = getDepth(root.left);
int rightDepth = getDepth(root.right);
if (leftDepth == rightDepth) {// 左子树是满二叉树
// 2^leftDepth其实是 (2^leftDepth - 1) + 1 ,左子树 + 根结点
return (1 << leftDepth) + countNodes(root.right);
} else {// 右子树是满二叉树
return (1 << rightDepth) + countNodes(root.left);
}
}
public int getDepth(TreeNode node) {
int depth = 0;
while (node != null) {
node = node.left;
depth++;
}
return depth;
}
5、平衡二叉树
public boolean isBalanced(TreeNode root) {
return height(root) >= 0;
}
public int height(TreeNode root){
if (root == null) return 0;
int left = height(root.left);
int right = height(root.right);
if (left == -1 || right == -1 || Math.abs(left-right) > 1) return -1;
else return Math.max(left,right) + 1;
}
6、二叉树的所有路径
// 递归
List<String> resList;
public List<String> binaryTreePaths(TreeNode root) {
resList = new ArrayList<>();
if (root == null) return resList;
getPath(root, new ArrayList<>());
return resList;
}
public void getPath(TreeNode node, List<Integer> path) {
path.add(node.val);
if (node.left == null && node.right == null) {
resList.add(getPathString(path));
return;
}
if (node.left != null) {
getPath(node.left, path);
path.remove(path.size() - 1);
}
if (node.right != null) {
getPath(node.right, path);
path.remove(path.size() - 1);
}
}
private String getPathString(List<Integer> path) {
StringBuilder builder = new StringBuilder();
builder.append(path.get(0));
for (int i = 1; i < path.size(); i++) {
builder.append("->").append(path.get(i));
}
return builder.toString();
}
7、左叶子之和
// 递归
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) return 0;
if (root.left != null && root.left.left == null && root.left.right == null) return root.left.val + sumOfLeftLeaves(root.right);
else return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
}
8、找左下角的值
public int findBottomLeftValue(TreeNode root) {
Queue<TreeNode> queue = new ArrayDeque<>();
queue.offer(root);
while (!queue.isEmpty()) {
root = queue.poll();
// 先右后左,最后一个就是最左边的叶子节点
if (root.right != null) queue.offer(root.right);
if (root.left != null) queue.offer(root.left);
}
return root.val;
}
9、路经总和
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) return false;
if (root.left == null && root.right == null) return targetSum == root.val;
targetSum -= root.val;
return hasPathSum(root.left, targetSum) || hasPathSum(root.right, targetSum);
}
四、二叉树的构造与修改
1、反转二叉树
// 递归
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
TreeNode tmp = root.left;
root.left = invertTree(root.right);
root.right = invertTree(tmp);
return root;
}
2、中序后续遍历序列构造二叉树
// 注意这个方法!
int[] inorder;
int[] postorder;
int index_post;
Map<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] inorder, int[] postorder) {
this.inorder = inorder;
this.postorder = postorder;
index_post = postorder.length-1;
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
return helper(0, inorder.length-1);
}
private TreeNode helper(int left, int right) {
if (left > right) return null;
TreeNode node = new TreeNode(postorder[index_post]);
int index = map.get(postorder[index_post--]);
node.right = helper(index + 1, right);
node.left = helper(left, index - 1);
return node;
}
public TreeNode buildTree(int[] inorder, int[] postorder) {
return buildTreeUnit(inorder, 0, inorder.length-1, postorder, 0, postorder.length-1);
}
public TreeNode buildTreeUnit(int[] inorder, int i, int j, int[] postorder, int x, int y) {
if (i > j || x > y) return null;
int k = i;
for (; k <= j; k++) {
if (inorder[k] == postorder[y]) break;
}
TreeNode root = new TreeNode(postorder[y]);
root.left = buildTreeUnit(inorder, i, k-1, postorder, x, x+k-i-1);
root.right = buildTreeUnit(inorder, k+1, j, postorder, x+k-i, y-1);
return root;
}
3、最大二叉树
public TreeNode constructMaximumBinaryTree(int[] nums) {
return constructBinaryTree(nums, 0, nums.length-1);
}
public TreeNode constructBinaryTree(int[] nums, int l, int r) {
if (l > r) return null;
if (l == r) return new TreeNode(nums[l]);
// 寻找范围内最大值
int index = l;
int max = nums[l];
for (int i = l+1; i <= r; i++) {
if (nums[i] > max) {
index = i;
max = nums[i];
}
}
TreeNode root = new TreeNode(max);
root.left = constructBinaryTree(nums, l, index - 1);
root.right = constructBinaryTree(nums, index + 1, r);
return root;
}
4、合并二叉树
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null && root2 == null) return null;
if (root1 == null) return root2;
if (root2 == null) return root1;
TreeNode node = new TreeNode();
node.val = root1.val + root2.val;
node.left = mergeTrees(root1.left, root2.left);
node.right = mergeTrees(root1.right, root2.right);
return node;
}
5、最近公公祖先
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) { // 递归结束条件
return root;
}
// 后序遍历
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(left == null && right == null) { // 若未找到节点 p 或 q
return null;
}else if(left == null && right != null) { // 若找到一个节点
return right;
}else if(left != null && right == null) { // 若找到一个节点
return left;
}else { // 若找到两个节点
return root;
}
}
五、二叉搜索树的属性
1、二叉搜索树中的搜索
public TreeNode searchBST(TreeNode root, int val) {
if (root == null) return null;
if (root.val == val) return root;
return root.val > val ? searchBST(root.left, val) : searchBST(root.right, val);
}
2、验证二叉搜索树
注意这道题,不能简单粗暴的判断左右两个节点跟该节点的比较。
// 递归
TreeNode max;
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
// 左
boolean left = isValidBST(root.left);
if (!left) return false;
// 中
if (max != null && max.val >= root.val) return false;
max = root;
// 右
boolean right = isValidBST(root.right);
return right;
}
// 迭代
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
Stack<TreeNode> stack = new Stack<>();
TreeNode prev = null;
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
TreeNode node = stack.pop();
if (prev != null && prev.val >= node.val) return false;
prev = node;
root = node.right;
}
return true;
}
3、二叉搜索树的最小绝对差
// 递归1
int min = Integer.MAX_VALUE;
TreeNode prev;
public int getMinimumDifference(TreeNode root) {
getMinimum(root);
return min;
}
public void getMinimum(TreeNode root) {
if (root == null) return;
getMinimum(root.left);
if (prev != null) min = Math.min(min, root.val - prev.val);
prev = root;
getMinimum(root.right);
}
// 递归2
int min = Integer.MAX_VALUE;
TreeNode prev;
public int getMinimumDifference(TreeNode root) {
if (root == null) return min;
min = getMinimumDifference(root.left);
if (prev != null) min = Math.min(min, root.val - prev.val);
prev = root;
return getMinimumDifference(root.right);
}
// 迭代
int min = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode prev = null;
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
TreeNode pop = stack.pop();
if (prev != null) min = Math.min(min, pop.val - prev.val);
prev = pop;
root = pop.right;
}
return min;
}
4、二叉搜索树中的众数
注意这道题,用到很多小点
List<Integer> resList;
TreeNode prev;
int maxCount;
int count;
public int[] findMode(TreeNode root) {
resList = new ArrayList<>();
prev = null;
maxCount = 0;
count = 0;
findModeUnit(root);
return resList.stream().mapToInt(Integer::intValue).toArray();
}
public void findModeUnit(TreeNode root) {
if (root == null) return;
findModeUnit(root.left);
// 中
if (prev == null || prev.val != root.val) {
count = 1;
} else if (prev.val == root.val) {
count++;
}
// 如果root的值和前一个指针的值不相等
// 当前的count是前一个指针的值的个数,与maxCount进行比较
// 1、如果小于maxCount,就直接跳过,将count设置为1即可
// 2、如果等于maxCount,就直接讲prev的值假如到resList中
// 3、如果大于maxCount,就将resList清空,更新maxCount的值,将prev的值加入resList中
if (count == maxCount) {
resList.add(root.val);
} else if (count > maxCount) {
maxCount = count;
resList.clear();
resList.add(root.val);
}
prev = root;
findModeUnit(root.right);
}
5、二叉树转换为累加树
// 递归
int addition = 0;
public TreeNode convertBST(TreeNode root) {
if (root == null) return null;
root.right = convertBST(root.right);
root.val += addition;
addition = root.val;
root.left = convertBST(root.left);
return root;
}
// 迭代
public TreeNode convertBST(TreeNode root) {
if (root == null) return null;
Stack<TreeNode> stack = new Stack<>();
int addition = 0;
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
if (cur != null) {
stack.push(cur);
cur = cur.right;
}else {
cur = stack.pop();
cur.val += addition;
addition = cur.val;
cur = cur.left;
}
}
return root;
}
六、二叉搜索树的构造与修改
1、二叉搜索树中的插入操作
// 递归
public TreeNode insertIntoBST(TreeNode root, int val) {
if (root == null) return new TreeNode(val);
if (root.val < val) root.right = insertIntoBST(root.right, val);
else root.left = insertIntoBST(root.left, val);
return root;
}
// 迭代
public TreeNode insertIntoBST(TreeNode root, int val) {
if (root == null) return new TreeNode(val);
TreeNode cur = root;
TreeNode prev = root;
while (cur != null) {
prev = cur;
if (cur.val < val) cur = cur.right;
else if (cur.val > val) cur = cur.left;
}
if (prev.val > val) prev.left = new TreeNode(val);
else prev.right = new TreeNode(val);
return root;
}
2、二叉搜索树中的删除操作
删除有五种情况,需要注意这道题
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) return root;
if (root.val < key) root.right = deleteNode(root.right, key);
else if (root.val > key) root.left = deleteNode(root.left, key);
else {
// root.val==key
// 1、叶子节点
// 2、左孩子为空,右孩子不为空
// 3、右孩子为空,左孩子不为空
if (root.left == null) return root.right;
if (root.right == null) return root.left;
// 4、左右孩子都不为空
TreeNode tmp = root.right;
while (tmp.left != null) {
tmp = tmp.left;
}
tmp.left = root.left;
return root.right;
}
return root;
}
3、修剪二叉搜索树
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) return null;
if (root.val < low) return trimBST(root.right, low, high);
if (root.val > high) return trimBST(root.left, low, high);
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
return root;
}
4、有序数组转换为二叉搜索树
public TreeNode sortedArrayToBST(int[] nums) {
if (nums == null || nums.length == 0) return null;
return sortedArrayToBST1(nums, 0, nums.length-1);
}
public TreeNode sortedArrayToBST1(int[] nums, int left, int right) {
if (left > right) return null;
int mid = left + (right - left) / 2;
TreeNode root = new TreeNode(nums[mid]);
root.left = sortedArrayToBST1(nums, left, mid-1);
root.right = sortedArrayToBST1(nums, mid+1, right);
return root;
}
5、最近公公祖先
// 递归
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q);
if (root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q);
return root;
}
// 迭代
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while (true) {
if (root.val < p.val && root.val < q.val) root = root.right;
else if (root.val > p.val && root.val > q.val) root = root.left;
else return root;
}
}