当前位置: 首页 > news >正文

二叉树相关OJ题练习

1. 二叉树的最大深度。OJ链接

class Solution {public int maxDepth(TreeNode root) {if (root == null) {return 0;}int leftHeight = maxDepth(root.left);int rightHeight = maxDepth(root.right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;}
}

2. 检查两棵树是否相同。OJ链接

如下图所示实例即为两棵相同的树。

 如下图就是两棵不同的树:结构不同。

如下图也是两棵不同的树:值不同。

 注意题目要求:结构上相同,即左右子树及其值要相同。

首先可以先判断结构上是否相同,如果两树的相同位置的子树一个为空一个为空就两树就不同,如果两树的相同位置的子树都为空,两树相同,如果两树相同位置但子树都不为空,那么判断里面的值是否一样,值一样就往下判断它的左右子树是否相同,相同了两棵树才完全相同。

class Solution {//时间复杂度:O(min(M,N))public boolean isSameTree(TreeNode p, TreeNode q) {if(p != null && q == null || p == null && q != null){return false;}if(p == null && q == null){return true;}if(p.val != q.val){return false;}return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);}
}

 3. 另一棵树的子树。OJ链接

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

class Solution {//时间复杂度:root:有r个节点   subRoot:有s个节点      O(|s|*|t|)public boolean isSubtree(TreeNode root, TreeNode subRoot) {if(root == null || subRoot == null){return false;}//1. 判断两棵树是不是相同的树if(isSameTree(root, subRoot)){return true;}//2. subRoot是不是root的左子树if(isSubtree(root.left, subRoot)){return true;}//3. subRoot是不是root的右子树if(isSubtree(root.right, subRoot)){return true;}return false;}public boolean isSameTree(TreeNode p, TreeNode q) {//详见上题代码}
}

4. 反转二叉树。OJ链接

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

class Solution {public TreeNode invertTree(TreeNode root) {if(root == null){return null;}TreeNode tmp = root.left;root.left = root.right;root.right = tmp;invertTree(root.left);invertTree(root.right);return root;}
}

5. 平衡二叉树。OJ链接

一颗高度平衡的二叉树的定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

时间复杂度为O(n^2):

class Solution {public int maxDepth(TreeNode root) {//详见上文求二叉树深度}public boolean isBalanced(TreeNode root) {if(root == null){return true;}int leftH = maxDepth(root.left);int rightH = maxDepth(root.right);return Math.abs(leftH - rightH) < 2 &&isBalanced(root.left) && isBalanced(root.right);}
}

以上代码,会有重复求深度的问题,浪费了时间,改进代码,使时间复杂度为O(n):

class Solution {public int maxDepth(TreeNode root) {if (root == null) {return 0;}int leftHeight = maxDepth(root.left);if (leftHeight < 0) {return -1;}int rightHeight = maxDepth(root.right);if(leftHeight >= 0 && rightHeight >= 0 &&Math.abs(leftHeight - rightHeight) <= 1){return Math.max(leftHeight,rightHeight) + 1;   // 返回真实的高度}else{return -1;}}public boolean isBalanced(TreeNode root) {if(root == null){return true;}return maxDepth(root) >= 0;}
}

6. 对称二叉树。OJ链接

class Solution {public boolean isSymmetric(TreeNode root) {if(root == null){return true;}return isSymmetricChild(root.left, root.right);}private boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree) {// 左树为空 右树不为空 或者 左树不为空 右树为空if(leftTree != null && rightTree == null ||leftTree == null && rightTree != null) {return false;}// 左树和右树都为空if(leftTree == null &&rightTree == null) {return true;}// 左树和右树都不为空if(leftTree.val != rightTree.val) {return false;}// 往下一层继续判断return isSymmetricChild(leftTree.left,rightTree.right) &&isSymmetricChild(leftTree.right,rightTree.left);}
}

7. 二叉树的层序遍历。OJ链接

题目中,要求把每一层的值放进list中,所以问题的焦点在于如何确定二叉树的这一层。

我们通过队列不断的出队入队可以得到想要的结果,下面以下图为例讲解。

当根不为空时将其(即A)放入队列,然后队列不为空,此时队列中有一个节点,这个队列的size为1,将其弹出给cur,同时这一个节点作为新申请一个list的第一层,size--为0。然后再把cur的左和右放进队列(即B、C),那么此时队列不为空且size为2,于是接下来这一层list中就放B和C。执行同样的操作,把B弹出给cur同时也放进新list中,然后将B的左和右放进队列,此时size--后为1,再将C放进list,size--为0,此时这个list就是第二层,然后将C的左右放进队列,这时队列中就是第三层了,以此类推。

class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> list = new ArrayList<>();if (root == null) {return list;}Queue<TreeNode> qu = new LinkedList<>();qu.offer(root);while (!qu.isEmpty()) {int size = qu.size();List<Integer> tmp = new ArrayList<>();while (size > 0) {TreeNode cur = qu.poll();size--;tmp.add(cur.val);if (cur.left != null) {qu.offer(cur.left);}if (cur.right != null) {qu.offer(cur.right);}}list.add(tmp);//易漏注意!}return list;}
}

8. 二叉树的构建及遍历。OJ链接

编一个程序,读入用户输入的一串先序遍历(即前序遍历)字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

题干中可以读到,#确定了空树的位置,所以很容易画出该二叉树。

 由于题目给的是先根遍历的字符串,所以需要先拿到字符串的每一个字符。对字符串进行遍历,如果拿到的不是“#”而是字符,就表明拿到的是节点。

import java.util.Scanner;class TreeNode {public char val;public TreeNode left;public TreeNode right;public TreeNode(char val) {this.val = val;}
}// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseString str = in.nextLine();TreeNode root = createTree(str);//中序遍历这棵二叉树inOrder(root);}}public static void inOrder(TreeNode root) {if (root == null) {return;}inOrder(root.left);System.out.print(root.val + " ");inOrder(root.right);}private static int i = 0;private static TreeNode createTree(String str) {TreeNode root = null;if (str.charAt(i) != '#') {root = new TreeNode(str.charAt(i));i++;root.left = createTree(str);root.right = createTree(str);} else {i++;}return root;}
}

9. 二叉树的最近公共祖先。OJ链接

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

第一种思路:利用两个栈分别存储祖先节点到p和祖先节点到p的节点,比较两栈大小并将大的栈弹出元素直至两栈大小相同,然后两栈再同时弹出元素,当弹出的元素相同时即为公共祖先。

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if(root == null || p == null || q == null){return null;}Stack<TreeNode> stack1 = new Stack<>();getPath(root, p, stack1);Stack<TreeNode> stack2 = new Stack<>();getPath(root, q, stack2);int size1 = stack1.size();int size2 = stack2.size();if(size1 > size2){int size = size1 - size2;while(size > 0){stack1.pop();size--;}}else{int size = size2 - size1;while(size > 0){stack2.pop();size--;}}//两栈中一定是相同的节点个数while(stack1.peek() != stack2.peek()){stack1.pop();stack2.pop();}return stack1.peek();}private boolean getPath(TreeNode root, TreeNode node, Stack<TreeNode> stack){if(root == null || node == null){return false;}stack.push(root);if(root == node){return true;}boolean flg1 = getPath(root.left, node, stack);if(flg1 == true){return true;}boolean flg2 = getPath(root.right, node, stack);if(flg2 == true){return true;}stack.pop();return false;}
}

第二种思路: 二叉搜索树

二叉搜索树的概念:根节点比左子树大,比右子树小(递归的),当对其进行中序遍历时结果是有序的。

所以如果有x、y两个节点,寻找它们的公共祖先,就可能出现如下的情况:

(1)x、y其中一个是根节点,公共祖先就是x或y;

(2)x、y在根节点两侧,公共祖先就是root;

(3)x、y在root的左子树或者在root右子树中。

将本题代入上述各个情况:

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if(root == null){return null;}if(root == p || root == q){return root;}TreeNode leftTree = lowestCommonAncestor(root.left, p, q);TreeNode rightTree = lowestCommonAncestor(root.right, p, q);if(leftTree != null && rightTree != null){return root;}else if(leftTree != null){return leftTree;}else if(rightTree != null){return rightTree;}else{return null;}}
}

10. 二叉搜索树转化成排序的双向链表。OJ链接

public class Solution {TreeNode prev = null;public TreeNode Convert(TreeNode pRootOfTree) {if(pRootOfTree == null){return null;}convertChild(pRootOfTree);TreeNode head = pRootOfTree;while(head.left != null){head = head.left;}return head;}private void convertChild(TreeNode pCur){if(pCur == null){return;}convertChild(pCur.left);pCur.left = prev;if(prev != null){prev.right = pCur;}prev = pCur;convertChild(pCur.right);}
}

11. 二叉树前序遍历非递归实现。OJ链接、

需要定义一个引用cur,通过cur来遍历这棵树。

首先有一个栈,定义一个cur指向root。

如果cur不为空,就把cur当前所指向的节点A放入栈中,同时把A打印。

接下来cur往左边走为B,将B入栈并打印。然后再往左走为D,将D入栈并打印。

再往左走,cur为空了。这时对于D这棵树的根走完了,左也走完了,接下来就看D的右边,这时弹出D给到top,然后让cur指向当前D的右边,也为空,那么相当于D这棵树左走完了,然后再弹出B给到top,让cur指向B的右。以此类推。

class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> ret = new ArrayList<>();TreeNode cur = root;Stack<TreeNode> stack = new Stack<>();while (cur != null || !stack.isEmpty()) {while (cur != null) {stack.push(cur);ret.add(cur.val);cur = cur.left;}TreeNode top = stack.pop();cur = top.right;}return ret;}
}

12. 二叉树中序遍历非递归实现。OJ链接

class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> ret = new ArrayList<>();TreeNode cur = root;Stack<TreeNode> stack = new Stack<>();while (cur != null || !stack.isEmpty()) {while (cur != null) {stack.push(cur);cur = cur.left;}TreeNode top = stack.pop();ret.add(top.val);cur = top.right;}return ret;}
}

13. 二叉树后序遍历非递归实现。OJ链接

class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> ret = new ArrayList<>();TreeNode cur = root;Stack<TreeNode> stack = new Stack<>();TreeNode prev = null;while (cur != null || !stack.isEmpty()) {while (cur != null) {stack.push(cur);cur = cur.left;}TreeNode top = stack.peek();if (top.right == null || top.right == prev) {ret.add(top.val);stack.pop();prev = top;} else {cur = top.right;}}return ret;}
}

14. 根据前中序遍历构建二叉树。OJ链接

class Solution {public int preIndex = 0;public TreeNode buildTree(int[] preorder, int[] inorder) {return buildTreeChild(preorder, inorder, 0, inorder.length-1);}private TreeNode buildTreeChild(int[] preorder, int[] inorder, int inbegin, int inend){//1. 判断当前根节点是否有左子树或者右子树if(inbegin > inend){return null;}TreeNode root = new TreeNode(preorder[preIndex]);//2. 找到root在中序遍历的位置int rootIndex = findIndex(inorder, inbegin, inend, preorder[preIndex]);preIndex++;if(rootIndex == -1){return null;}//3. 构建左子树和右子树root.left = buildTreeChild(preorder, inorder, inbegin, rootIndex-1);root.right = buildTreeChild(preorder, inorder, rootIndex+1, inend);return root;}private int findIndex(int[] inorder, int inbegin, int inend, int val){for(int i = inbegin; i <= inend; i++){if(inorder[i] == val){return i;}}return -1;}
}

15. 根据中后序遍历构建二叉树。OJ链接

class Solution {public int postIndex = 0;public TreeNode buildTree(int[] inorder, int[] postorder) {postIndex = postorder.length-1;return buildTreeChild(postorder, inorder, 0, inorder.length-1);}private TreeNode buildTreeChild(int[] postorder, int[] inorder, int inbegin, int inend){//1. 判断当前根节点是否有左子树或者右子树if(inbegin > inend){return null;}TreeNode root = new TreeNode(postorder[postIndex]);//2. 找到root在中序遍历的位置int rootIndex = findIndex(inorder, inbegin, inend, postorder[postIndex]);postIndex--;if(rootIndex == -1){return null;}//3. 构建左子树和右子树root.right = buildTreeChild(postorder, inorder, rootIndex+1, inend);root.left = buildTreeChild(postorder, inorder, inbegin, rootIndex-1);return root;}private int findIndex(int[] inorder, int inbegin, int inend, int val){for(int i = inbegin; i <= inend; i++){if(inorder[i] == val){return i;}}return -1;}
}

16. 二叉树创建字符串。OJ链接

class Solution {public String tree2str(TreeNode root) {StringBuilder stringBuilder = new StringBuilder();tree2strChild(root, stringBuilder);return stringBuilder.toString();}public void tree2strChild(TreeNode t, StringBuilder stringBuilder){if(t == null){return;}stringBuilder.append(t.val);if(t.left != null){stringBuilder.append("(");tree2strChild(t.left, stringBuilder);stringBuilder.append(")");}else{if(t.right == null){return;}else{stringBuilder.append("()");}}if(t.right == null){return;}else{stringBuilder.append("(");tree2strChild(t.right, stringBuilder);stringBuilder.append(")");}}
}

http://www.mrgr.cn/news/77756.html

相关文章:

  • vscode 远程连接ssh 密钥方式
  • JavaWeb后端开发知识储备2
  • 【Vue】 npm install amap-js-api-loader指南
  • Spring |(二)IOC相关内容 | bean
  • Python世界:力扣题解875,珂珂爱吃香蕉,中等
  • 论文复现_How Machine Learning Is Solving the Binary Function Similarity Problem
  • 2024 APMCM亚太数学建模C题 - 宠物行业及相关产业的发展分析和策略 完整参考论文(1)
  • DrissionPage爬虫工具教程
  • Node基本使用
  • java学习记录12
  • <OS 有关> ubuntu 24 不同版本介绍 安装 Vmware tools
  • 项目实践----springboot中设计基于Redisson的分布式锁注解
  • 实用功能,觊觎(Edge)浏览器的内置截(长)图功能
  • oracle排查长时间没提交的事务造成的阻塞案例
  • Spring循环依赖如何解决的?
  • Pytorch使用手册-Datasets DataLoaders(专题三)
  • 学习日志015--python单链表
  • Mybatis,Druid,lombok
  • hhdb数据库介绍(10-1)
  • 瑞佑液晶控制芯片RA6807系列介绍 (三)软件代码详解 Part.8(实现淡入淡出效果)
  • Pytorch使用手册-快速开始(专题一)
  • Pytorch使用手册-Tensors(专题二)
  • AP+AC组网——STA接入
  • Java项目实战II基于微信小程序的校运会管理系统(开发文档+数据库+源码)
  • 51c大模型~合集76
  • 如何将文件Copy到Docker镜像中