给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
其经典解法是递归操作!maxDepth(root) = max(maxDepth(root.left), maxDepth(root.right)) + 1没有什么多余的复杂操作,就是这么一行经典代码!但是这里面用到的思想则是类似DFS(深度优先搜索算法),这个也是要求掌握的,下面会一并给出!
class Solution {
public int maxDepth(TreeNode root) {
if (root==null){
return 0;
}
int left=maxDepth(root.left);
int right=maxDepth(root.right);
return Math.max(left,right)+1;
}
}
二叉树的DFS实现,很重要希望你能掌握!
private List<TreeNode> traversal(TreeNode root) {
List<TreeNode> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
stack.add(root);
while (!stack.empty()) {
TreeNode node = stack.peek();
res.add(node);
stack.pop();
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
return res;
}
给定一个二叉树,返回其按层次遍历的节点值。(即逐层地,从左到右访问所有节点)。
例如:
给定二叉树: [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:[[3],[9,20],[15,7]]
二叉树的层次遍历,经典的BFS方法,借助队列来实现!你同样要掌握的哦!再次声明,二叉树的DFS和BFS一定要会!
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res=new ArrayList<>();
if (root==null){
return res;
}
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()){
int queuesize=queue.size();
List<Integer> tmp=new ArrayList<>();
for (int i=0;i<queuesize;i++){
TreeNode node=queue.remove();
tmp.add(node.val);
if (node.left!=null){
queue.add(node.left);
}
if (node.right!=null){
queue.add(node.right);
}
}
res.add(new ArrayList<>(tmp));
}
return res;
}
}
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
首先你要明白二叉搜索树的定义。
二叉搜索树(Binary Search Tree),(又:二叉查找树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;它的左、右子树也分别为二叉搜索树。
是的,不只是满足当前节点的只值大于左子节点的值,更是要整个左子树的值都小于当前节点的值,右子树也是如此!那么开始时,我们需要初始化两个值min和max,对 我们选用long型的MIN_VALUE和MAX_VALUE,然后进行递归求解,每次我们遍历到一个节点,看当前节点是否满足,该节点值大于左子节点并且小于右子节点,不满足返回false,满足那么还需验证该节点的左、右子树是否也满足这个条件!
class Solution {
public boolean isValidBST(TreeNode root) {
if (root==null){
return true;
}
return isBST(root,Long.MIN_VALUE,Long.MAX_VALUE);
}
public boolean isBST(TreeNode root,long min,long max){
if (root==null){
return true;
}
if (min>=root.val||max<=root.val){
return false;
}
return isBST(root.left,min,root.val)&&isBST(root.right,root.val,max);
}
}
给定二叉搜索树(BST)的根节点和一个值。你需要在BST中找到节点值等于给定值的节点。返回以该节点为根的子树。如果节点不存在,则返回 NULL。
上面我们了解了二叉搜索树的概念,那么要查找一个节点,我们按照BST的特性即可,即对比查找的值与当前节点值的大小,小于则在左子树中寻找,大于则在右子树中寻找,要么中途找到返回节点,要么遍历到根节点返回null!
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
while (root!=null){
if (root.val==val){
return root;
}else if (root.val<val){
root=root.right;
}else {
root=root.left;
}
}
return null;
}
}
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
说明:要求算法时间复杂度为 O(h),h 为树的高度。
我们要删除BST的一个节点,首先需要找到该节点。而找到之后,会出现三种情况。
1.待删除的节点左子树为空,让待删除节点的右子树替代自己。
2.待删除的节点右子树为空,让待删除节点的左子树替代自己。
3.如果待删除的节点的左右子树都不为空。我们需要找到比当前节点小的最大节点(前驱),来替换自己或者比当前节点大的最小节点(后继),来替换自己。
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if (root==null){
return null;
}
if (key<root.val){
root.left=deleteNode(root.left,key);
return root;
}
if (key>root.val){
root.right=deleteNode(root.right,key);
return root;
}
if (root.right==null){
return root.left;
}
if (root.left==null){
return root.right;
}
TreeNode minNode=root.right;
while (minNode.left!=null){
minNode=minNode.left;
}
root.val=minNode.val;
root.right=deleteMinNode(root.right);
return root;
}
public TreeNode deleteMinNode(TreeNode root){
if (root.left==null){
TreeNode pRight=root.right;
root.right=null;
return pRight;
}
root.left=deleteMinNode(root.left);
return root;
}
}
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
题目中给了平衡二叉树的概念,左子树与右子树的高度差不超过1,而且是任意一颗子树都需要满足这个条件的!关于二叉树的高度,我们上面已经给出了求解方法!即递归求解中,除了验证当前节点是否满足左右子树高度差不超过1,还需要继续验证其左右子树是否也满足此条件!
class Solution {
public boolean isBalanced(TreeNode root) {
if (root==null){
return true;
}
int leftDepth=depth(root.left);
int rightDepth=depth(root.right);
if (Math.abs(leftDepth-rightDepth)>1){
return false;
}
return isBalanced(root.left)&&isBalanced(root.right);
}
public int depth(TreeNode root){
if (root==null){
return 0;
}
int left=depth(root.left);
int right=depth(root.right);
return Math.max(left,right)+1;
}
}
给出一个完全二叉树,求出该树的节点个数。
说明:
完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
首先我们要知道对于一个满二叉树,其h层一共包含有2^h个节点,那么对于本题来说完全二叉树就是最后一层,并不是每个节点的度都是2,而且节点集中在左边排列。那么我们需要做的就是先求出左右子树的高度,如果出现左右子树高度相等,那么说明左子树是颗满二叉树,叶子节点已经排到右子树了,那么对于总的节点个数就是 2^left-1再加上跟节点,再递归求解右子树!如果左右子树高度不等,即左子树大于右子树高度,那么证明右子树是颗满二叉树,总的节点个数等于2 ^right-1再加上根节点,然后递归求解左子树!
class Solution {
public int countNodes(TreeNode root) {
if (root==null){
return 0;
}
int left=countLevel(root.left);
int right=countLevel(root.right);
if (left==right){
return (1<<left)+countNodes(root.right);
}else {
return (1<<right)+countNodes(root.left);
}
}
public int countLevel(TreeNode root){
if (root==null){
return 0;
}
int left=countLevel(root.left);
int right=countLevel(root.right);
return Math.max(left,right)+1;
}
}
给定二叉树根结点 root ,此外树的每个结点的值要么是 0,要么是 1。返回移除了所有不包含 1 的子树的原二叉树。
依据题意,我们要删除的节点一定满足以下条件:该节点左右子树为空,且该节点的值为0,那么将该节点设置为null即可!
class Solution {
public TreeNode pruneTree(TreeNode root) {
return deal(root);
}
public TreeNode deal(TreeNode root){
if (root==null){
return null;
}
root.left=deal(root.left);
root.right=deal(root.right);
if (root.left==null&&root.right==null&&root.val==0){
return null;
}
return root;
}
}
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
这是剑指offer上一道非常高频的题目!解题思路可以借用堆来做,本题需要用到大顶堆!在开始时,堆中元素小于k个时,先向堆中加入元素,由于题目要求最小的k个数,所以我们用大顶堆,每次将堆顶元素与遍历元素相比较,如果遍历元素小于堆顶元素,那么将堆顶元素poll,然后将当前遍历元素加入堆中,否则继续遍历!到最后遍历结束后,堆中留存的k个数就是最小的k个!这个思路一定要掌握!
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if(k>=arr.length){
return arr;
}
if (k==0||arr.length==0){
return new int[0];
}
PriorityQueue<Integer> queue=new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
for (int num:arr){
if (queue.size()<k){
queue.add(num);
}else if (queue.peek()>num){
queue.poll();
queue.add(num);
}
}
int[] res=new int[k];
int index=0;
for (int num:queue){
res[index++]=num;
}
return res;
}
}
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
字节一面上来手撕的第一道题!这你敢说不会? 思路就是依据前序遍历(跟左右,首个元素为根节点)的第一个元素,去中序遍历中查找相应节点(中序为左根右)找到相应节点相当于在中序遍历中找到了根节点的左右子树,然后左右子树中再重复上述思路继续寻找子树的左右子树节点!
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return reconstruct(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
}
public TreeNode reconstruct(int[] pre,int startpre,int endpre,int[] in,int startin,int endin){
if (startpre>endpre||startin>endin){
return null;
}
TreeNode root=new TreeNode(pre[startpre]);
for (int i=startin;i<=endin;i++){
if (in[i]==pre[startpre]){
root.left=reconstruct(pre,startpre+1,startpre+i-startin,in,startin,i-1);
root.right=reconstruct(pre,startpre+i-startin+1,endpre,in,i+1,endin);
break;
}
}
return root;
}
}
请实现两个函数,分别用来序列化和反序列化二叉树。
比较容易想到的序列化思路就是前序遍历(根左右),这样反序列化时也好还原树结构。即先取出根节点然后依次取出左右子树节点!
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if(root==null){
return "#,";
}
StringBuffer res=new StringBuffer(root.val+",");
res.append(serialize(root.left));
res.append(serialize(root.right));
return res.toString();
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
String[] str=data.split(",");
Queue<String> queue=new LinkedList<>();
for (int i=0;i<str.length;i++){
queue.offer(str[i]);
}
return pre(queue);
}
public TreeNode pre(Queue<String> queue){
String val=queue.poll();
if (val.equals("#")){
return null;
}
TreeNode node=new TreeNode(Integer.parseInt(val));
node.left=pre(queue);
node.right=pre(queue);
return node;
}
}
输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
递归一套下来!
class Solution {
List<List<Integer>> res=new ArrayList<>();
List<Integer> path=new ArrayList<>();
public List<List<Integer>> pathSum(TreeNode root, int sum) {
recur(root,sum);
return res;
}
public void recur(TreeNode root,int target){
if (root==null){
return;
}
path.add(root.val);
target-=root.val;
if (target==0&&root.left==null&&root.right==null){
res.add(new ArrayList<>(path));
}
recur(root.left,target);
recur(root.right,target);
path.remove(path.size()-1);
}
}
本题来源于Leetcode中 归属于二叉树类型题目。
同许多在算法道路上不断前行的人一样,不断练习,修炼自己!
如有博客中存在的疑问或者建议,可以在下方留言一起交流,感谢各位!
觉得本博客有用的客官,可以给个点赞+收藏哦! 嘿嘿
喜欢本系列博客的可以关注下,以后除了会继续更新面试手撕代码文章外,还会出其他系列的文章!