二叉树问题一般通过前序遍历、中序遍历、后序遍历以及层序遍历就可以解决,涉及的算法主要为BFS(层次遍历)、DFS(回溯,递归)。
二叉树的最大深度
int ans=0;
int depth=0;
public int maxDepth(TreeNode root) {
//递归做法
// if(root==null) return 0;
// return Math.max(maxDepth(root.left),maxDepth(root.right))+1;
//遍历,前序就是进入节点的时候,后序就是退出节点的时候
dfs(root);
return ans;
}
void dfs(TreeNode root){
if(root==null){
return;
}
depth++;
dfs(root.left);
dfs(root.right);
ans=Math.max(ans,depth); //labuladong的做法是前序判断叶节点更新ans
depth--;
}
124 二叉树的最大路径和
int ans=Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
dfs(root);
return ans;
}
int dfs(TreeNode root){
if(root==null) return 0;
int left=dfs(root.left);
int right=dfs(root.right);
int tmp= root.val;
if(left>=0){
tmp+=left;
}
if(right>=0){
tmp+=right;
}
ans=Math.max(ans,tmp);
//要不要左右子树取决于加入子树后该节点的值是不是比当前节点大
return Math.max(root.val,Math.max(left,right)+root.val);
}
102 二叉树的层序遍历
public List<List<Integer>> levelOrder(TreeNode root) {
if(root==null) return new ArrayList<>();
List<List<Integer>> ans=new ArrayList<>();
Queue<TreeNode> q=new LinkedList<>();
q.offer(root);
while(q.size()!=0){
List<Integer> tmp=new ArrayList<>();
int curSize=q.size();
for(int i=0;i<curSize;i++){
TreeNode node=q.poll();
tmp.add(node.val);
if(node.left!=null) q.offer(node.left);
if(node.right!=null) q.offer(node.right);
}
ans.add(tmp);
}
return ans;
}
617 合并二叉树
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1==null) return root2;
if(root2==null) return root1;
TreeNode merge= new TreeNode(root1.val+root2.val);
merge.left=mergeTrees(root1.left,root2.left);
merge.right=mergeTrees(root1.right,root2.right);
return merge;
}
230 二叉搜索树中第K小的数
int ans;
int k;
public int kthSmallest(TreeNode root, int k) {
this.k=k;
dfs(root);
return ans;
}
void dfs(TreeNode root){
if(root==null) return;
dfs(root.left);
k--;
if(k==0) ans=root.val;
dfs(root.right);
}
226 翻转二叉树
public TreeNode invertTree(TreeNode root) {
if (root==null) return null;
// 需要暂存root.left,避免覆盖
TreeNode node=root.left;
root.left=invertTree(root.right);
root.right=invertTree(node);
return root;
}
101 对称二叉树
public boolean isSymmetric(TreeNode root) {
if(root==null) return true;
return dfs(root.left,root.right);
}
boolean dfs(TreeNode left,TreeNode right){
if(left==null && right==null) return true;
if(left==null || right==null) return false;
return (left.val==right.val) && dfs(left.left,right.right)
&& dfs(left.right,right.left);
}
543 二叉树的直径
int ans;
public int diameterOfBinaryTree(TreeNode root) {
ans=1;
depth(root);
return ans-1;
}
//返回当前节点的深度
int depth(TreeNode root){
if (root==null) return 0;
int l=depth(root.left);
int r=depth(root.right);
ans=Math.max(ans,l+r+1);
return Math.max(l,r)+1;
}
222 完全二叉树的节点个数
int ans=0;
public int countNodes(TreeNode root) {
dfs(root);
return ans;
}
void dfs(TreeNode root){
if(root==null) return ;
ans++;
dfs(root.left);
dfs(root.right);
}
257 二叉树的所有路径
List<String> ans=new ArrayList<>();
StringBuilder sb=new StringBuilder();
public List<String> binaryTreePaths(TreeNode root) {
dfs(root);
return ans;
}
void dfs(TreeNode root){
if(root==null) return;
int t=sb.length();
sb.append(root.val);
if(root.left==null && root.right==null){
ans.add(sb.toString());
}else{
sb.append("->");
}
dfs(root.left);
dfs(root.right);
//离开叶节点时一步一步删除
sb.delete(t,sb.length());
}
404 左叶子之和
int ans;
public int sumOfLeftLeaves(TreeNode root) {
dfs(root);
return ans;
}
void dfs(TreeNode root){
if(root==null) return ;
if(root.left!=null && root.left.left==null && root.left.right==null)
ans+=root.left.val;
dfs(root.left);
dfs(root.right);
}
501 二叉搜索树中的众数
HashMap<Integer,Integer> map=new HashMap<>();
public int[] findMode(TreeNode root) {
dfs(root);
List<Integer> ans=new ArrayList<>();
//得到最大次数
int maxTime=0;
for(Integer k: map.keySet()){
int temp=map.get(k);
maxTime=temp>=maxTime? temp:maxTime;
}
//得到ans
for(Integer v: map.keySet()){
if(map.get(v)==maxTime){
ans.add(v);
}
}
return ans.stream().mapToInt(Integer::valueOf).toArray();
}
void dfs(TreeNode root){
if (root==null) return;
dfs(root.left);
int key=root.val;
map.put(key,map.getOrDefault(key,0)+1);
dfs(root.right);
}
530 二叉树的最小绝对差
List<Integer> list=new ArrayList<>();
public int getMinimumDifference(TreeNode root) {
dfs(root);
int ans=Integer.MAX_VALUE;
for(int i=0;i< list.size()-1;i++){
if(ans>(list.get(i+1)-list.get(i))){
ans=list.get(i+1)-list.get(i);
}
}
return ans;
}
void dfs(TreeNode root){
if (root==null) return ;
dfs(root.left);
list.add(root.val);
dfs(root.right);
}
563 二叉树的坡度
public int findTilt(TreeNode root) {
if (root==null) return 0;
return findTilt(root.left)+findTilt(root.right)+sum(root);
}
int sum(TreeNode root){
return Math.abs(recur(root.left)-recur(root.right));
}
int recur(TreeNode root){
if (root==null) return 0;
int l=recur(root.left);
int r=recur(root.right);
return l+r+root.val;
}
572 另一棵树的子树
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
return dfs(root,subRoot);
}
boolean dfs(TreeNode root, TreeNode subRoot){
if (root==null) return false;
return check(root,subRoot)
|| isSubtree(root.left,subRoot) || isSubtree(root.right,subRoot);
}
boolean check(TreeNode root, TreeNode subRoot){
if(root==null && subRoot==null)
return true;
if(root==null || subRoot==null || root.val!=subRoot.val)
return false;
return check(root.left,subRoot.left)
&& check(root.right,subRoot.right);
}
//提交2
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root==null || subRoot==null)
return false;
return dfs(root,subRoot) || isSubtree(root.left,subRoot)
|| isSubtree(root.right,subRoot);
}
boolean dfs(TreeNode root, TreeNode subRoot){
if(root==null && subRoot==null)
return true;
if(root==null || subRoot==null || root.val!=subRoot.val)
return false;
return dfs(root.left,subRoot.left)
&& dfs(root.right,subRoot.right);
}
637 二叉树的层平均值
public List<Double> averageOfLevels(TreeNode root) {
List<Double> ans=new ArrayList<>();
if (root==null) return ans;
Queue<TreeNode> pq=new LinkedList<>();
pq.add(root);
while (!pq.isEmpty()){
int curSize=pq.size();
double level=0;
int count=0;
for(int i=0;i<curSize;i++){
TreeNode node=pq.poll();
level+=node.val;
count++;
if(node.left!=null) pq.add(node.left);
if(node.right!=null) pq.add(node.right);
}
ans.add(level/count);
}
return ans;
}
653 两数之和-二叉搜索树
HashSet<Integer> set=new HashSet<>();
public boolean findTarget(TreeNode root, int k) {
return dfs(root,k);
}
//返回当前k-当前节点值的值是否在set中
boolean dfs(TreeNode root,int k){
if(root==null) return false;
if (set.contains(k-root.val)){
return true;
}
set.add(root.val);
return dfs(root.left,k) || dfs(root.right,k);
}
671 二叉树中第二小的节点
Set<Integer> set=new HashSet<>();
public int findSecondMinimumValue(TreeNode root) {
dfs(root);
//记住set,list转数组的做法-stream流的方式
int[] arr=set.stream().mapToInt(Integer::intValue).toArray();
Arrays.sort(arr);
return arr.length<=1? -1:arr[1];
}
void dfs(TreeNode root){
if(root==null) return;
set.add(root.val);
dfs(root.left);
dfs(root.right);
}
700 二叉搜索树中的搜索
TreeNode ans;
public TreeNode searchBST(TreeNode root, int val) {
dfs(root,val);
return ans;
}
void dfs(TreeNode root,int val){
if (root==null) return;
if(root.val==val) ans=root;
dfs(root.left,val);
dfs(root.right,val);
}
872 叶子相似的树
public boolean leafSimilar(TreeNode root1, TreeNode root2) {
List<Integer> set1=new ArrayList<>();
dfs(root1,set1);
List<Integer> set2=new ArrayList<>();
dfs(root2,set2);
if (set1.size()==set2.size()){
for(int i=0;i<set1.size();i++){
if(!set1.get(i).equals(set2.get(i))) return false;
}
return true;
}
return false;
}
void dfs(TreeNode root,List<Integer> s){
if(root==null) return ;
if(root.left==null && root.right==null){
s.add(root.val);
}
dfs(root.left,s);
dfs(root.right,s);
}
897 递增顺序搜索树
List<Integer> ans=new ArrayList<>();
public TreeNode increasingBST(TreeNode root) {
TreeNode dumy=new TreeNode() ;
TreeNode temp=dumy;
dfs(root);
for(int i=0;i< ans.size();i++){
temp.right=new TreeNode(ans.get(i));
temp=temp.right;
}
return dumy.right;
}
void dfs(TreeNode root){
if(root==null) return;
dfs(root.left);
ans.add(root.val);
dfs(root.right);
}
938 二叉搜索树的范围和
int ans;
public int rangeSumBST(TreeNode root, int low, int high) {
dfs(root,low,high);
return ans;
}
void dfs(TreeNode root,int low,int high){
if (root==null) return;
if(root.val>=low && root.val<=high) ans+=root.val;
dfs(root.left,low,high);
dfs(root.right,low,high);
}
965 单值二叉树
List<Integer> list=new ArrayList<>();
public boolean isUnivalTree(TreeNode root) {
int n;
if(root==null) return false;
else n=root.val;
boolean flag;
dfs(root);
for(int i=1;i<list.size();i++){
if(list.get(i)!=n){
return false;
}
}
return true;
}
void dfs(TreeNode root){
if(root==null) return;
list.add(root.val);
dfs(root.left);
dfs(root.right);
}
993 二叉树的堂兄弟节点
public boolean isCousins(TreeNode root, int x, int y) {
Queue<TreeNode> pq=new LinkedList<>();
pq.add(root);
while(!pq.isEmpty()){
int sz=pq.size();
int countX=0,countY=0;
for(int i=0;i<sz;i++){
TreeNode node=pq.poll();
if(node.val==x) countX=1;
if(node.val==y) countY=1;
if(node.left!=null && node.right!=null){
int left=node.left.val,right=node.right.val;
if((left==x && right==y) || (right==x&&left==y))
return false;
}
if (node.left!=null) pq.add(node.left);
if(node.right!=null) pq.add(node.right);
}
if(countX==1&&countY==1) return true;
}
return false;
}
1379 找出克隆二叉树中的相同节点
TreeNode ans;
public final TreeNode getTargetCopy(final TreeNode original, final TreeNode cloned, final TreeNode target) {
dfs(cloned,target);
return ans;
}
void dfs(TreeNode cloned,TreeNode target){
if (cloned==null) return ;
if(cloned.val==target.val) ans=cloned;
dfs(cloned.left,target);
dfs(cloned.right,target);
}
2236 判断根节点是否等于子结点之和
public boolean checkTree(TreeNode root) {
int tar;
if (root==null) return false;
else tar= root.val;
return (dfs(root.left)+dfs(root.right))==tar;
}
int dfs(TreeNode root){
if (root==null) return 0;
return root.val+dfs(root.left)+dfs(root.right);
}
2331 计算布尔二叉树的值
public boolean evaluateTree(TreeNode root) {
if (root.left==null) return root.val==1;
if(root.val==2){
return evaluateTree(root.left) || evaluateTree(root.right);
}else{
return evaluateTree(root.left) && evaluateTree(root.right);
}
}
LCP44 开幕式焰火
Set<Integer> set=new HashSet<>();
public int numColor(TreeNode root) {
dfs(root);
return set.size();
}
void dfs(TreeNode root){
if (root==null) return;
set.add(root.val);
dfs(root.left);
dfs(root.right);
}
面试04.02 最小高度树
//将中间的树当根节点,左边当左子树,右边右子树
public TreeNode sortedArrayToBST(int[] nums) {
return dfs(nums,0,nums.length-1);
}
TreeNode dfs(int[] nums,int i,int j){
if(i>j) return null;
int mid=(int)Math.ceil((i+j)/2.0);
TreeNode node=new TreeNode(nums[mid]) ;
node.left=dfs(nums,i,mid-1);
node.right=dfs(nums,mid+1,j);
return node;
}
04.04 检查平衡性
public boolean isBalanced(TreeNode root) {
if (root==null) return true;
return Math.abs(height(root.left)-height(root.right))<=1
&& isBalanced(root.left)
&& isBalanced(root.right);
}
int height(TreeNode root){
if (root==null) return 0;
return Math.max(height(root.left),height(root.right))+1;
}
LCR144 翻转二叉树
public TreeNode mirrorTree(TreeNode root) {
return dfs(root);
}
TreeNode dfs(TreeNode root){
if(root==null) return null;
//思考为什么不能TreeNode ans=root;不知道是不是内存引用的问题,new创建新的引用,=去堆中找
TreeNode ans=new TreeNode(root.val);
ans.left=dfs(root.right);
ans.right=dfs(root.left);
return ans;
}
LCR 144 推理(重建)二叉树
//借助辅助结构,全局preorder,以及map
int[] preorder;
Map<Integer,Integer> map=new HashMap<>();
public TreeNode deduceTree(int[] preorder, int[] inorder) {
this.preorder=preorder;
for (int i=0;i<inorder.length;i++){
map.put(inorder[i],i);
}
return recur(0,0,inorder.length-1);
}
TreeNode recur(int root, int left, int right){ //根节点位置,子树的左端-右端
if(left>right) return null;
TreeNode node=new TreeNode(preorder[root]);
//map记录了前序的节点在中序的索引,方便分割
int i=map.get(preorder[root]);
node.left=recur(root+1,left,i-1); //递归分段-左子树
//右子树,右子树的根索引计算方式为:根节点索引+左子树长度+1
node.right=recur(root+i-left+1,i+1,right);
return node;
}