1.二叉树的最大深度
题目要求:
难度:🌟
解答:
- 递归+DFS
- 树的总深度 = max(左子树深度,右子树深度) + 当前节点所在的一层深度
class Solution {
public int maxDepth(TreeNode root) {
if(root == null){
return 0;
}
int leftHeight=maxDepth(root.left);
int rightHeight=maxDepth(root.right);
return Math.max(leftHeight,rightHeight)+1;
}
}
2.翻转二叉树
题目要求:
难度:🌟
解答:
- 反转=把二叉树上的每一个节点的左右子节点进行交换
- 递归的交换当前节点的左节点,递归的交换当前节点的右节点
- 再交换当前节点的左右节点
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null){
return null;
}
TreeNode left=invertTree(root.left);
TreeNode right=invertTree(root.right);
root.left=right;
root.right=left;
return root;
}
}
3.填充每个节点的下一个右侧节点指针
题目要求:
难度:🌟🌟
解答:
- BFS
- 在遍历每一行的时候,只要把他们串联起来就OK
class Solution {
public Node connect(Node root) {
if(root == null){
return root;
}
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
int curLrvelNum = queue.size();//记录每层的节点数 循环时更新
Node pre=null;
for(int i=0;i<curLrvelNum;i++){
Node curNode = queue.poll();
//如果pre为空就表示node节点是这一行的第一个,
//没有前一个节点指向他,否则就让前一个节点指向他
if (pre != null) {
pre.next = curNode;
}
//然后再让当前节点成为下次循环的前一个节点
pre=curNode;
//子节点入队
if (curNode.left != null){
queue.add(curNode.left);
}
if (curNode.right != null){
queue.add(curNode.right);
}
}
}
return root;
}
}
- 纵向递归DFS
-
每个 node 左子树的 next , 就是 node 的右子树
-
每个 node 右子树的 next, 就是 node next 的 左子树
public Node connect(Node root) {
dfs(root, null);
return root;
}
private void dfs(Node curr, Node next) {
if (curr == null)
return;
curr.next = next;
dfs(curr.left, curr.right);
dfs(curr.right, curr.next == null ? null : curr.next.left);
}
4.二叉树展开为链表
题目要求:
难度:🌟🌟
解答:
- 递归 将左右子树处理
- 将
x
的右子树接到左子树下方,然后将整个左子树作为右子树
class Solution {
public void flatten(TreeNode root) {
if(root == null){
return ;
}
flatten(root.left);
flatten(root.right);
TreeNode left=root.left;
TreeNode right=root.right;
root.left=null;
root.right=left;
//最后拼接
TreeNode P=root;
while(P.right != null){
P=P.right;
}
P.right=right;
}
}
5.最大二叉树
题目要求:
难度:🌟🌟
解答:
- 递归
- 当前
nums
中的最大值就是根节点,然后根据索引递归调用左右数组构造左右子树即可
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return build(nums, 0, nums.length - 1);
}
public TreeNode build(int[] nums,int left,int right) {
if(left>right){
return null;
}
int index=-1;
int maxVal=Integer.MIN_VALUE;
//找到最大值
for(int i=left;i<=right;i++){
if(maxVal<nums[i]){
maxVal=nums[i];
index=i;
}
}
//构造
TreeNode root=new TreeNode(maxVal);
root.left=build(nums,left,index-1);
root.right=build(nums,index+1,right);
return root;
}
}
6.从前序与中序遍历序列构造二叉树
题目要求:
难度:🌟🌟
解答:
- 递归,利用前序遍历在中序遍历中划分左右子树。
- 用一个 HashMap 存储元素到索引的映射
class Solution {
//key:元素值。 val:元素在中序遍历中的下标
HashMap<Integer, Integer> valToIndex = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
for(int i=0;i<inorder.length;i++){
valToIndex.put(inorder[i],i);
}
return buildTree(preorder,0,preorder.length-1,
inorder,0,inorder.length-1);
}
public TreeNode buildTree(int[] preorder,int preStart,int preEnd,
int[] inorder,int inStart,int inEnd) {
if(preStart > preEnd){
return null;
}
//取出当前根结点
int currRootVal=preorder[preStart];
int currIndex=valToIndex.get(currRootVal);
TreeNode currNode=new TreeNode(currRootVal);
int leftSize=currIndex - inStart;//左子树 节点个数
currNode.left=buildTree(preorder,preStart + 1,preStart+leftSize,
inorder,inStart,currIndex - 1);
currNode.right=buildTree(preorder,preStart + leftSize + 1,preEnd,
inorder,currIndex+1,inEnd);
return currNode;
}
}
7.寻找重复的子树
题目要求:
难度:🌟🌟
解答:
- DFS+StringBuilder去拼接子树+HashMap记录出现次数
- 使用
"_"
分割不同的节点值,同时对空节点进行保留(定义为空串" "
)
class Solution {
HashMap<String, Integer> recordMap = new HashMap<>();
List<TreeNode> answer=new ArrayList<>();
public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
DFS(root);
return answer;
}
public String DFS(TreeNode root){
if(root == null){
return " ";
}
StringBuilder currTree = new StringBuilder();
currTree.append(root.val).append("_");
currTree.append(DFS(root.left)).append(DFS(root.right));
String key=currTree.toString();
recordMap.put(key, recordMap.getOrDefault(key, 0) + 1);
if(recordMap.get(key) == 2){
answer.add(root);
}
return key;
}
}
8.二叉搜索树中第K小的元素
题目要求:
难度:🌟🌟
解答:
- BST 的中序遍历其实就是升序排序的结果
class Solution {
int res=0;
int rank=0;
public int kthSmallest(TreeNode root, int k) {
// 利用 BST 的中序遍历特性
traverse(root, k);
return res;
}
public void traverse(TreeNode root, int k){
if(root == null){
return;
}
traverse(root.left, k);
//中序遍历内容
rank++;
if(k == rank){
res=root.val;
return;
}
traverse(root.right,k);
}
}
9.从二叉搜索树到更大和树
题目要求:
难度:🌟🌟
解答:
- 利用 BST 的中序遍历特性,把递归顺序改一下(右 中 左),降序打印 BST
- 维护一个外部累加变量
sum
,然后把sum
赋值给 BST 中的每一个节点 -
PS:那么每个节点都去计算右子树的和,不就行了吗?这是不行的。对于一个节点来说,确实右子树都是比它大的元素,但问题是它的父节点也可能是比它大的元素呀?这个没法确定的,我们又没有触达父节点的指针,所以二叉树的通用思路在这里用不了。
class Solution {
public TreeNode bstToGst(TreeNode root) {
traverse(root);
return root;
}
int sum = 0;
public void traverse(TreeNode root){
if(root == null){
return;
}
traverse(root.right);
sum = sum + root.val;
root.val=sum;
traverse(root.left);
}
}
10. 验证二叉搜索树
题目要求:
难度:🌟🌟
解答:
- 将值的上下限传入递归,进行比较。
if (root.left != null && root.left.val >= root.val) return false;
if (root.right != null && root.right.val <= root.val) return false;
- 代码仅仅检查了它的左右孩子节点是否符合左小右大的原则;不能全面检查左右子树的情况
class Solution {
public boolean isValidBST(TreeNode root) {
return isValidBST(root,null,null);
}
public boolean isValidBST(TreeNode root, TreeNode min, TreeNode max){
if(root == null) return true;
if(min != null&&root.val <= min.val) return false;
if(max != null&&root.val >=max.val) return false;
return isValidBST(root.left,null,root) && isValidBST(root.right,root,null);
}
}
11.删除二叉搜索树中的节点
题目要求:
难度:🌟🌟
解答:
- 先找到该节点 ,再删除
- 情况 1:
A
恰好是末端节点,两个子节点都为空,直接删除。 - 情况 2:
A
只有一个非空子节点,那么它要让这个孩子接替自己的位置。 - 情况 3:
A
有两个子节点,A
必须找到左子树中最大的那个节点,或者右子树中最小的那个节点来接替自己。 - 以找到右子树中最小为例:
- 先找到最小的那个节点,用指针指向他
- 在右子树中删除它
- 将当前跟节点替换成最小节点
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null) return null;
if(root.val == key){
if(root.left == null) return root.right;
if(root.right == null) return root.left;
// 获得右子树最小的节点
TreeNode minNodeInRight=getMin(root.right);
// 删除右子树最小的节点
root.right = deleteNode(root.right, minNodeInRight.val);
// 用右子树最小的节点替换 root 节点
minNodeInRight.left = root.left;
minNodeInRight.right = root.right;
root = minNodeInRight;
}else if(root.val > key){
root.left=deleteNode(root.left,key);
}else if(root.val < key){
root.right=deleteNode(root.right,key);
}
return root;
}
public TreeNode getMin(TreeNode node) {
// BST 最左边的就是最小的
while (node.left != null) node = node.left;
return node;
}
}
12.不同的二叉搜索树
题目要求:
难度:🌟🌟
解答:
class Solution {
public int numTrees(int n) {
int dp[]=new int[n+1];
dp[0]=1;
dp[1]=1;
for(int i =2;i<n+1;i++){
for(int k=1;k<i+1;k++){
dp[i]+=dp[k-1]*dp[i-k];
}
}
return dp[n];
}
}