根据前序遍历和中序遍历序列构建二叉树
public TreeNode buildTree(int[] preorder, int[] inorder) {
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i],i);
}
return buildTreeDfs(preorder,inorder,0,0,preorder.length - 1);
}
private TreeNode buildTreeDfs(int[] preorder, int[] inorder, int preLeft, int inLeft, int inRight) {
if (inRight < inLeft) {
return null;
}
//根节点在中序遍历的位置
int rootIndex = map.get(preorder[preLeft]);
int leftNum = rootIndex - inLeft;
TreeNode root = new TreeNode(preorder[preLeft]);
//递归构建左子树
root.left = buildTreeDfs(preorder,inorder,preLeft + 1,inLeft,rootIndex - 1);
//递归构建右子树
root.right = buildTreeDfs(preorder,inorder,preLeft + leftNum + 1,rootIndex + 1,inRight);
return root;
}
二叉搜索树迭代器
class BSTIterator {
Deque<TreeNode> stack;
TreeNode root;
public BSTIterator(TreeNode root) {
stack = new LinkedList<>();
while (root != null) {
stack.push(root);
root = root.left;
}
}
public int next() {
TreeNode pop = stack.pop();
TreeNode right = pop.right;
while (right != null) {
stack.push(right);
right = right.left;
}
return pop.val;
}
public boolean hasNext() {
return stack.size() > 0;
}
}
二叉树右视图
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) {
return res;
}
Deque<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
LinkedList<Integer> level = new LinkedList<>();
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode poll = queue.poll();
level.addFirst(poll.val);
if (poll.left != null) {
queue.offer(poll.left);
}
if (poll.right != null) {
queue.offer(poll.right);
}
}
res.add(level.getFirst());
}
return res;
}
完全二叉树的节点个数
public int countNodes(TreeNode root) {
if (root == null) {
return 0;
}
int leftDepth = depth(root.left);
int rightDepth = depth(root.right);
//左右子树高度相等则左子树是满二叉树,只需要遍历右子树
if (leftDepth == rightDepth) {
//1 << leftDepth相当于左子树的数量+根节点
return (1 << leftDepth) + countNodes(root.right);
//左右子树不高度相等则右子树是满二叉树,只需要遍历左子树
} else {
return (1 << rightDepth) + countNodes(root.left);
}
}
private int depth(TreeNode root) {
int depth = 0;
while (root != null) {
depth++;
root = root.left;
}
return depth;
}
路径总和|||
int count = 0;
public int pathSum(TreeNode root, int targetSum) {
//key是前缀和 value是该前缀和出现的次数
Map<Integer, Integer> preSumMap = new HashMap<>();
//前缀和为0的出现了一次,就是一个节点都没有时
preSumMap.put(0,1);
pathSumDfs(root,preSumMap,targetSum,0);
return count;
}
private void pathSumDfs(TreeNode root, Map<Integer, Integer> preSumMap, int target, int curSum) {
if (root == null) {
return;
}
curSum += root.val;
//先找后更新前缀和
if (preSumMap.containsKey(curSum - target)) {
count += preSumMap.get(curSum - target);
}
preSumMap.put(curSum,preSumMap.getOrDefault(curSum,0) + 1);
pathSumDfs(root.left,preSumMap,target,curSum);
pathSumDfs(root.right,preSumMap,target,curSum);
//回溯恢复现场,去除当前节点的前缀和数量,因为这个路径不可能是别的路径的前缀了
//恢复现场是因为路径方向必须是向下的(只能从父节点到子节点)一个节点必须是另一个节点的祖先节点
//例如遍历完最左边的3,然后遍历-2时是不包含21这条前缀和,因为路径只能从父节点到子节点,不能从子节点到父节点再到子节点
preSumMap.put(curSum,preSumMap.getOrDefault(curSum,0) - 1);
}
二叉树公共祖先
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (p == root || q == root) {
return root;
}
if (root == null) {
return null;
}
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if (left == null) {
return right;
}
if (right == null) {
return left;
}
return root;
}
打家劫舍|||
public int rob(TreeNode root) {
int[] res = robDfs(root);
return Math.max(res[0],res[1]);
}
public int[] robDfs(TreeNode root) {
if (root == null) {
return new int[2];
}
int [] left = robDfs(root.left);
int [] right = robDfs(root.right);
int[] dp = new int[2];
//当前节点偷,子节点不能偷
dp[0] = root.val + left[1] + right[1];
//当前节点不偷,子节点可以偷可以不偷
dp[1] = Math.max(left[0],left[1]) + Math.max(right[0],right[1]);
return dp;
}
最大二叉树
public TreeNode constructMaximumBinaryTree(int[] nums) {
return constructMaximumBinaryTreeDfs(nums,0,nums.length - 1);
}
public TreeNode constructMaximumBinaryTreeDfs(int[] nums, int left, int right) {
if (left > right) {
return null;
}
int res = Integer.MIN_VALUE;
int index = 0;
for (int i = left; i <= right; i++) {
if (nums[i] > res) {
res = nums[i];
index = i;
}
}
TreeNode root = new TreeNode(res);
root.left = constructMaximumBinaryTreeDfs(nums,left,index - 1);
root.right = constructMaximumBinaryTreeDfs(nums,index + 1,right);
return root;
}
树的子结构
每次遇到 A.val == B.val 就把现在的 A 结点当作根节点去 check,看是否两棵树的形状、值相同。
public boolean isSubStructure(TreeNode A, TreeNode B) {
if (B == null || A == null) {
return false;
}
//看是否两棵树的形状、值相同
if (A.val == B.val && isSubStructureDfs(A,B)) {
return true;
} else {
//比较左子树或右子树是否包含B
return isSubStructure(A.left,B) || isSubStructure(A.right,B);
}
}
public boolean isSubStructureDfs(TreeNode a, TreeNode b) {
//B遍历完了即找到了可以返回true
if (b == null) {
return true;
}
//A遍历完或A的值和B的值不相等
if (a == null || a.val != b.val) {
return false;
}
return isSubStructureDfs(a.left,b.left) && isSubStructureDfs(a.right,b.right);
}
二叉树中和为某一值的路径
LinkedList<List<Integer>> pathSum;
public List<List<Integer>> pathSum(TreeNode root, int target) {
pathSum = new LinkedList<>();
LinkedList<Integer> path = new LinkedList<>();
pathSumDfs(root,target,path);
return pathSum;
}
private void pathSumDfs(TreeNode root, int target, LinkedList<Integer> path) {
if (root == null) {
return;
}
path.add(root.val);
if (root.val == target && root.left == null && root.right == null) {
pathSum.add(new LinkedList<>(path));
path.removeLast(); //找到一条路径要回溯恢复现场
return;//这里return相当于不遍历叶子节点的左右节点提前返回了所以要回溯把最后一个元素remove掉
}
pathSumDfs(root.left,target - root.val,path);
pathSumDfs(root.right,target - root.val,path);
path.removeLast();
}
LinkedList<List<Integer>> pathSum;
public List<List<Integer>> pathSum(TreeNode root, int target) {
pathSum = new LinkedList<>();
LinkedList<Integer> path = new LinkedList<>();
pathSumDfs(root,target,path);
return pathSum;
}
private void pathSumDfs(TreeNode root, int target, LinkedList<Integer> path) {
if (root == null) {
return;
}
path.add(root.val);
if (root.val == target && root.left == null && root.right == null) {
pathSum.add(new LinkedList<>(path));
//这里不return相当于会遍历叶子节点的左右节点所以不用在这里回溯,遍历完叶子节点的左右节点之后会回溯
}
pathSumDfs(root.left,target - root.val,path);
pathSumDfs(root.right,target - root.val,path);
path.removeLast();
}
相同的树
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) {
return true;
}
if (p == null || q == null || p.val != q.val) {
return false;
}
return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}
对称二叉树
public boolean isSymmetric(TreeNode root) {
return isSymmetricDfs(root.left,root.right);
}
private boolean isSymmetricDfs(TreeNode left, TreeNode right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null || left.val != right.val) {
return false;
}
return isSymmetricDfs(left.left,right.right) && isSymmetricDfs(left.right,right.left);
}
二叉树的最大深度
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
//加1表示的是根节点
return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
}
将有序数组转换为二叉搜索树
public TreeNode sortedArrayToBST(int[] nums) {
return sortedArrayToBSTDfs(nums,0,nums.length - 1);
}
private TreeNode sortedArrayToBSTDfs(int[] nums, int left, int right) {
if (left > right) {
return null;
}
int mid = (left + right) / 2;
TreeNode root = new TreeNode(nums[mid]);
root.left = sortedArrayToBSTDfs(nums,0,mid - 1);
root.right = sortedArrayToBSTDfs(nums,mid + 1,right);
return root;
}
平衡二叉树
public boolean isBalanced(TreeNode root) {
if (root == null) {
return true;
}
int abs = Math.abs(maxDepth(root.left) - maxDepth(root.right));
//isBalanced(root) root永远是true的递归没有出口所以不能这样写
// return isBalanced(root) && isBalanced(root.left) && isBalanced(root.right);
return abs <= 1 && isBalanced(root.left) && isBalanced(root.right);
}
路径总和
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) {
return false;
}
if (targetSum == root.val && root.left == null && root.right == null) {
return true;
}
boolean left = hasPathSum(root.left,targetSum - root.val);
boolean right = hasPathSum(root.right,targetSum - root.val);
return left || right;
}
翻转二叉树
public TreeNode invertTree(TreeNode root) {
if (root == null) {
return null;
}
TreeNode left = invertTree(root.left);
TreeNode right = invertTree(root.right);
root.right = left;
root.left = right;
return root;
}
二叉搜索树的最近公共祖先
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//根节点都比p,q大就在左找
if (root.val > p.val && root.val > q.val) {
return lowestCommonAncestor(root.left,p,q);
}
//根节点都比p,q大就在右找
if (root.val < p.val && root.val < q.val) {
return lowestCommonAncestor(root.right,p,q);
}
//走到这里root有可能等于p或等于q,有可能小于p大于q
return root;
}
二叉树的直径
int diameter = Integer.MIN_VALUE;
public int diameterOfBinaryTree(TreeNode root) {
diameterOfBinaryTreeDfs(root);
return diameter;
}
public int diameterOfBinaryTreeDfs(TreeNode root) {
if (root == null) {
return 0;
}
//当前节点左子树高度
int leftDepth = diameterOfBinaryTreeDfs(root.left);
//当前节点右子树高度
int rightDepth = diameterOfBinaryTreeDfs(root.right);
//计算当前节点的左子树高度+右子树高度,如果比之前算出的大就更新
diameter = Math.max(leftDepth + rightDepth,diameter);
//当前节点高度,返回给leftDepth或rightDepth使用
return 1 + Math.max(leftDepth,rightDepth);
}
二叉搜索树的第k大节点
int kthLargest = 0;
int kthCount = 0;
public int kthLargest(TreeNode root, int k) {
if (root == null) {
return 0;
}
kthLargest(root.right,k);
kthCount++;
if (k == kthCount) {
kthLargest = root.val;
}
kthLargest(root.left,k);
return kthLargest;
}
合并二叉树
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null) {
return root2;
}
if (root2 == null) {
return root1;
}
TreeNode root = new TreeNode(root1.val + root2.val);
root.left = mergeTrees(root1.left,root2.left);
root.right = mergeTrees(root1.right,root2.right);
return root;
}