【LeetCode Hot100】二叉树篇
前言
本文用于整理LeetCode Hot100中题目解答,因题目比较简单且更多是为了面试快速写出正确思路,只做简单题意解读和一句话题解方便记忆。但代码会全部给出,方便大家整理代码思路。
94. 二叉树的中序遍历
一句话题意
返回二叉树中序遍历的数值数组。
一句话题解
二叉树中序遍历是:先访问当前左节点,然后读取当前节点值,最后访问右节点。
模拟即可。
class Solution {List<Integer> ans = new ArrayList<>();public List<Integer> inorderTraversal(TreeNode root) {dfs(root);return ans;}void dfs(TreeNode node){if(node == null) return ;dfs(node.left);ans.add(node.val);dfs(node.right);}
}
104. 二叉树的最大深度
一句话题意
求二叉树最大深度。
一句话题解
二叉树最大深度也就是从根节点到叶子节点最大距离,模拟即可。
class Solution {int ans=0;void dfs(TreeNode node ,int dep){if(node==null){ans=Math.max(ans,dep);return ;}dfs(node.left,dep+1);dfs(node.right,dep+1);}public int maxDepth(TreeNode root) {dfs(root,0);return ans;}
}
226. 翻转二叉树
一句话题意
将二叉树中每个左右节点进行反转。
一句话题解
广搜然后模拟跑一下即可。
class Solution {public TreeNode invertTree(TreeNode root) {Queue<TreeNode> q = new LinkedList<>();if(root != null ) q.add(root);while(q.size() > 0){TreeNode x = q.poll();if(x==null)continue;TreeNode mid = x.left;x.left = x.right;x.right = mid;q.add(x.left);q.add(x.right); }return root;}
}
101. 对称二叉树
一句话题意
检查给定的二叉树是否根据根节点对称。
一句话题解
模拟。
class Solution {public boolean check(TreeNode l, TreeNode r){if(l==null&&r==null)return true;if((r==null&&l!=null)||(r!=null&&l==null)||(l.val!=r.val))return false;return check(l.left,r.right)&check(l.right,r.left);} public boolean isSymmetric(TreeNode root) {return check(root.left,root.right);}
}
543. 二叉树的直径
一句话题意
求树上两点距离的最大值,即树的直径。
一句话题解
当前节点的左子树最大深度+当前节点的右子树最大深度=以当前节点为中间点的最长链
class Solution {int ans;int dfs(TreeNode a){if(a==null)return 0;int l=dfs(a.left);int r=dfs(a.right);ans=Math.max(ans,l+r);return Math.max(l,r)+1;}public int diameterOfBinaryTree(TreeNode root) {dfs(root);return ans;}
}
102. 二叉树的层序遍历
一句话题意
将二叉树进行层序遍历,将值保留在二维数组中。
一句话题解
广搜层序遍历模拟即可。
class Solution {class Node {TreeNode node;int dep;Node(TreeNode node,int dep){this.node = node ;this.dep = dep;}}public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> ans = new ArrayList<>();Queue<Node> q = new LinkedList<>();q.add(new Node(root,0));while(q.size()>0){Node x = q.poll();if(x.node==null)continue;if(ans.size()<=x.dep)ans.add(new ArrayList<>());ans.get(x.dep).add(x.node.val);q.add(new Node(x.node.left,x.dep+1));q.add(new Node(x.node.right,x.dep+1));}return ans;}
}
108. 将有序数组转换为二叉搜索树
一句话题意
给定一个有序列表,将列表中的数据转化成一颗平衡二叉搜索树。
一句话题解
平衡二叉搜索树 AVL树的特点是,当前节点的左节点的值要比当前节点小,右节点的值要比当前节点大。并且树不能连续三个左偏或右偏(因为可以进行转化)。根据上述特点,用二分来模拟建树即可。
class Solution {int[] arr;TreeNode dfs(TreeNode node ,int l,int r){if(l>r)return null;int mid=l+r>>1;node.val = arr[mid];node.left = dfs(new TreeNode(),l , mid-1);node.right = dfs(new TreeNode(), mid+1,r);return node;}public TreeNode sortedArrayToBST(int[] nums) {arr=nums;return dfs(new TreeNode(),0,nums.length-1);}
}
98. 验证二叉搜索树
一句话题意
验证是否为二叉搜索树。
有效 二叉搜索树定义如下:
-
节点的左子树只包含 小于 当前节点的数。
-
节点的右子树只包含 大于 当前节点的数。
-
所有左子树和右子树自身必须也是二叉搜索树。
一句话题解
方法一:按照题意模拟,验证即可。
方法二:通过层序遍历,拿出数值数组,确保数值数组为递增序列即可验证时二叉搜索树。
class Solution {public boolean check(TreeNode node, long mn, long mx) {if (node == null)return true;if (node.val<= mn||node.val>=mx) return false;return check(node.left, mn, node.val) && check(node.right, node.val, mx);}public boolean isValidBST(TreeNode root) {return check(root, Long.MIN_VALUE, Long.MAX_VALUE);}
}
230. 二叉搜索树中第 K 小的元素
一句话题意
找到二叉搜索中第K小的元素。
一句话题解
中序遍历跑一遍二叉搜索树,每次读取中间节点值得时候K--,最后K为0时候取值即可。
class Solution {int ans;int cnt;void dfs(TreeNode node){if(node==null||cnt==0)return ;dfs(node.left);cnt--;if(cnt==0)ans=node.val;dfs(node.right);}public int kthSmallest(TreeNode root, int k) {ans=-1;cnt=k;dfs(root);return ans;}
}
199. 二叉树的右视图
一句话题意
给定一颗二叉树,求二叉树的每一层最右侧的节点。
一句话题解
先序遍历二叉树,每次访问节点的时候更新当前层的节点。
class Solution {List<Integer> ans =new ArrayList<>();public List<Integer> rightSideView(TreeNode root) {dfs(root,0);return ans;}void dfs(TreeNode node ,int dep){if(node==null)return ;if(ans.size()<=dep)ans.add(node.val);else ans.set(dep,node.val);dfs(node.left, dep+1);dfs(node.right,dep+1);}
}
114. 二叉树展开为链表
一句话题意
给定一颗二叉树,让这棵树变成一颗右偏树,展开后的链表的顺序应与先序遍历的顺序相同。不要使用额外空间。
一句话题解
优先去访问左节点,当访问到当前左节点存在右节点的时候,将右节点的最后一个拿出来,连接到当前前节点的右节点上,这样能保证右侧的链先连接成功。然后处理左节点,将左节点练到前一个节点的右节点上,然后左节点置空即可。
class Solution {public void flatten(TreeNode root) {while(root!=null){if(root.left!=null){TreeNode x= root.left;TreeNode y = x;while(y.right!=null){y=y.right;}y.right=root.right;root.left=null;root.right=x;}root=root.right;}}
}
105. 从前序与中序遍历序列构造二叉树
一句话题意
给定树的先序遍历和中序遍历,重新构建二叉树。
一句话题解
先序遍历的数组的第一节点是根节点,中序遍历可以判断出来根节点的左子树和右子树节点个数。
根据上面的两个特点,即可重新构造二叉树,即每次重复获取根节点,然后获取两侧个数,然后再去获取中间节点即可。用HashMap加速获取节点下表的速度。
class Solution {int[] pre;HashMap<Integer,Integer> mp=new HashMap<>();public TreeNode buildTree(int[] preorder, int[] inorder) {this.pre=preorder;for(int i=0;i<inorder.length;i++){mp.put(inorder[i],i);}return build(0,0,inorder.length-1);}TreeNode build(int root,int l,int r){if(l>r)return null;TreeNode node=new TreeNode(pre[root]);int mid=mp.get(pre[root]);node.left=build(root+1,l,mid-1);node.right=build(root+mid-l+1,mid+1,r);//mid-l左子树节点个数return node;}
}
437. 路径总和 III
一句话题意
求每个从父节点到父节点下面其中一个子节点的路径和为Target的路径个数。
一句话题解
从上到下做树形前缀和。
class Solution {int ans=0;int target;HashMap<Long,Integer> mp = new HashMap<>();public int pathSum(TreeNode root, int targetSum) {this.target=targetSum;mp.put(0L,1);dfs(root,0);return ans;}void dfs(TreeNode node,long sum){if(node==null)return ;sum+=node.val;ans+=mp.getOrDefault(sum - target,0);mp.put(sum,mp.getOrDefault(sum,0)+1);dfs(node.left,sum);dfs(node.right,sum);mp.put(sum,mp.get(sum)-1);}
}
236. 二叉树的最近公共祖先
一句话题意
求树任意两点的LCA。
一句话题解
先把所有节点的所属层数求出,然后根据层次结构往上跑父亲节点就可以了。
class Solution {HashMap<Integer,Integer> deep;HashMap<Integer,TreeNode> fa;public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {fa=new HashMap<Integer,TreeNode>();deep=new HashMap<Integer,Integer>();dfs(root,new TreeNode(-1),0);while(deep.get(p.val)>deep.get(q.val)){p=fa.get(p.val);}while(deep.get(p.val)<deep.get(q.val)){q=fa.get(q.val);}while(p.val!=q.val){p=fa.get(p.val);q=fa.get(q.val);}return p;}void dfs(TreeNode root,TreeNode faa,int dep){if(root==null)return ;deep.put(root.val,dep);fa.put(root.val,faa);dfs(root.left,root,dep+1);dfs(root.right,root,dep+1);}
}
124. 二叉树中的最大路径和
一句话题解
求二叉树任意两点间距离的最大值。
一句话题解
非常类似树的直接的思路,求当前节点左子树的最长链和右子树的最长链,加上自己本身,便是当前节点处于中点的最长路径。
class Solution {int ans = Integer.MIN_VALUE;public int maxPathSum(TreeNode root) {dfs(root);return ans;}int dfs(TreeNode node){if(node==null)return 0;int l = Math.max(dfs(node.left),0);int r = Math.max(dfs(node.right),0);ans=Math.max(ans,l+r+node.val);return node.val+Math.max(l,r);}
}