初学数据结构:二叉树相关oj题

目录

    • 1. 相同的树
    • 2. 另一棵树的子树
    • 3. 翻转二叉树
    • 4. 平衡二叉树
    • 5. 对称二叉树
    • 6. 二叉树构建与遍历
    • 7. 二叉树的层序遍历
    • 8. 二叉树的最近公共祖先
    • 9. 从前序与中序遍历序列构造二叉树
    • 10. 从中序与后序遍历序列构造二叉树
    • 11. 根据二叉树创建字符串
    • 12. 二叉树的前序遍历非递归实现
    • 13. 二叉树的中序遍历非递归实现
    • 14. 二叉树的后续遍历非递归实现

public class BinaryTree {class TreeNode{public int val;public TreeNode left;public TreeNode right;public TreeNode(int val) {this.val = val;}public TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}}//穷举法构建二叉树public TreeNode creatBinaryTree(){TreeNode A = new TreeNode(1);TreeNode B = new TreeNode(2);TreeNode C = new TreeNode(3);TreeNode D = new TreeNode(4);TreeNode E = new TreeNode(5);TreeNode F = new TreeNode(6);TreeNode G = new TreeNode(7);TreeNode H = new TreeNode(8);A.left = B;A.right = C;B.left = D;B.right = E;C.left = F;C.right = G;E.right = H;TreeNode root = A;return root;}
}

1. 相同的树

相同的树

思路:从子问题的角度去考虑

  • 首先,判断是否根结点处的结构相同,比如,两棵树的根结点是不是同时为空,或者一个为空另一个不为空,两个都不为空的四种情况,来判断结构
  • 其次,当两棵树的根结点都不为空时,判断是否元素相同
  • 最后,当元素相同时,判断两棵树根节点的左子树是否相同,右子树是否相同(递归)
class Solution {public boolean isSameTree(TreeNode p, TreeNode q) {if (p != null && q == null || p == null && q !=null) {//结构不一样return false;}//上述if语句没有进来,那么说明,要么两个都为空,要么两个都不是空if (p == null && q == null) {return true;}if (p.val != q.val) {return false;}//上述代码完成,走到这里,说明 p!=null && q!=null && p.val == q.valreturn isSameTree(p.left, q.left) && isSameTree(p.right, q.right);}
}

2. 另一棵树的子树

另一棵树的子树

思路:利用子问题递归解决

  • 首先判断root是否为空
  • 其次判断两棵树是否相同
  • 然后判断root为根结点的树的左子树与之是否相同
  • 最后判断root为根结点的树的右子树与之是否相同
class Solution {public boolean isSubtree(TreeNode root, TreeNode subRoot) {if (root == null) {return false;}if (isSameTree(root,subRoot)) {return true;}if (isSubtree(root.left, subRoot)){return true;}if (isSubtree(root.right, subRoot)){return true;}return false;}public boolean isSameTree(TreeNode p, TreeNode q) {if (p != null && q == null || p == null && q !=null) {//结构不一样return false;}//上述if语句没有进来,那么说明,要么两个都为空,要么两个都不是空if (p == null && q == null) {return true;}if (p.val != q.val) {return false;}//上述代码完成,走到这里,说明 p!=null && q!=null && p.val == q.valreturn isSameTree(p.left, q.left) && isSameTree(p.right, q.right);}
}

3. 翻转二叉树

翻转二叉树

  • 将根结点处的左子树与右子树翻转
  • 翻转左子树
  • 翻转右子树
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;}
}

4. 平衡二叉树

平衡二叉树

  • 如果根结点为空,则为平衡二叉树
  • 如果根结点不为空,求解左子树高度与右子树高度
    • 如果根结点左右子树高度差大于1,则不为平衡二叉树
    • 如果根结点左右子树高度差小于等于1,且左右子树均为平衡二叉树,则为平衡二叉树
public boolean isBalanced(TreeNode root) {if (root == null){return true;}int leftTreeHeight = getTreeHight(root.left);int rightTreeHeight = getTreeHight(root.right);int heightDifference = Math.abs(leftTreeHeight - rightTreeHeight);if(heightDifference > 1){return false;}else {return isBalanced(root.left) && isBalanced(root.right);}
}//用于求解树的高度
public int getTreeHight(TreeNode root){if(root == null){return 0;}if(root.left == null && root.right == null){return 1;}int leftHeight = getTreeHight(root.left);int rightHeight = getTreeHight(root.right);return Math.max(leftHeight, rightHeight) + 1;
}

5. 对称二叉树

对称二叉树

  • 根结点如果为空,则为对称二叉树
  • 根结点如果不为空:
    • 判断左结点与右结点在结构上是否对称
    • 判断左结点与右节点在数值上是否对称
    • 递归判断左子树与右子树是否对称
public class IsSymmetric {public boolean isSymmetric(TreeNode root) {if (root == null){return true;}return isSymmetricChild(root.left,root.right);}public boolean isSymmetricChild(TreeNode treeLeft, TreeNode treeRight) {//1.判断结构上是否对称if (treeLeft == null && treeRight != null || treeLeft != null && treeRight == null){return false;}if (treeLeft == null && treeRight == null){return true;}//2.判断数值上是否对称if (treeLeft.val != treeRight.val){return false;}//3.递归进行判断return isSymmetricChild(treeLeft.left, treeRight.right) && isSymmetricChild(treeLeft.right, treeRight.left);}
}

6. 二叉树构建与遍历

二叉树构建与遍历

利用二叉树前序遍历生成的字符串构建二叉树:

  • 构建根结点
  • 构建左子树
  • 构建右子树
class TreeNode {public char val;public TreeNode left;public TreeNode right;public TreeNode() {}public TreeNode(char val) {this.val = val;}public TreeNode(char val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}
import java.util.Scanner;public class BinaryTreeConstructionAndTraversal {//二叉树构建private static int i = 0;private static TreeNode BinaryTreeConstruction (String str){if (str == null){return null;}TreeNode root = null;if (str.charAt(i) != '#') {root = new TreeNode(str.charAt(i));i++;root.left = BinaryTreeConstruction(str);root.right = BinaryTreeConstruction(str);}else {i++;}return root;}//中序遍历private static void inOrder (TreeNode root){if (root == null){return;}inOrder(root.left);System.out.print(root.val + " ");inOrder(root.right);}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);while (scanner.hasNextLine()){String str = scanner.nextLine();TreeNode root = BinaryTreeConstruction(str);inOrder(root);}}
}

7. 二叉树的层序遍历

二叉树的层序遍历

将一层的元素加入顺序表当中,再将这些顺序表加入新的顺序表当中

在这里插入图片描述

public List<List<Character>> levelOrder(TreeNode root){List<List<Character>> retList = new ArrayList<>();if (root == null){return retList;}Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()){int size = queue.size();List<Character> list = new ArrayList<>();while (size != 0){TreeNode cur = queue.poll();list.add(cur.val);size--;if (cur.left != null){queue.offer(cur.left);}if (cur.right != null){queue.offer(cur.right);}}retList.add(list);}return retList;
}

8. 二叉树的最近公共祖先

二叉树的最近公共祖先

方法一:

  • 先判断p或者q 是不是 root当中的一个
  • 左子树当中查找p或者q(先查找到p就返回p,先查找到q就返回q)
  • 右子树当中查找p或者q(先查找到p就返回p,先查找到q就返回q)
  • 整体判断:
    • 左子树和右子树中都查找到了,则最近公共祖先为root
    • 如果左子树中没有查找到,则最近的公共祖先为右子树中查找到的
    • 如果右子树中没有查找到,则最近的公共祖先为左子树中查找到的
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if (root == null) {return null;}if (p == root || q == root) {return root;}TreeNode left = lowestCommonAncestor(root.left, p, q);TreeNode right = lowestCommonAncestor(root.right, p, q);if (left != null && right != null) {return root;}if (left == null) {return right;}return left;
}

方法二:

  • 求解p、q各自路径

  • 求解路径的相交点(大小做差,出栈)

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){Stack<TreeNode> stackp = new Stack<>();Stack<TreeNode> stackq = new Stack<>();int sizep = 0;int sizeq = 0;if (getPath(root, p, stackp)){sizep = stackp.size();}if (getPath(root, q, stackq)){sizeq = stackq.size();}int sizepq = sizep - sizeq;if (sizepq > 0){for (int i = 0; i < sizepq; i++) {stackp.pop();}}else {for (int i = 0; i < Math.abs(sizepq); i++) {stackq.pop();}}while (stackp.peek() != stackq.peek()){stackp.pop();stackq.pop();}return stackp.peek();
}

找到二叉树中node的所在路径

  • 判断是否为空
  • 判断是否等于node
  • 该结点入栈
  • 判断左子树是否存在路径
  • 判断右子树是否存在路径
  • 都不存在说明该结点不在路径上,出栈
public boolean getPath(TreeNode root, TreeNode node, Stack<TreeNode> stack){if (root == null){return false;}if (root == node){return true;}stack.push(root);boolean flgLeft = getPath(root.left, node, stack);if (flgLeft){return true;}boolean flgRight = getPath(root.right, node, stack);if (flgRight){return true;}stack.pop();return false;
}

9. 从前序与中序遍历序列构造二叉树

从前序与中序遍历序列构造二叉树

  • 创建根节点
  • 在中序遍历的字符串当中 找到当前根节点的下标
  • 分别创建左子树和右子树
public int preIndex;
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) {if (inBegin > inEnd) {return null;}// 1、创建根节点TreeNode root = new TreeNode(preorder[preIndex]);// 2. 在中序遍历的字符串当中 找到当前根节点的下标int rootIndex = findRootIndex(inorder,inBegin,inEnd,preorder[preIndex]);preIndex++;// F// 3. 分别创建左子树和右子树root.left = buildTreeChild(preorder, inorder, inBegin, rootIndex - 1);root.right = buildTreeChild(preorder, inorder, rootIndex + 1, inEnd);return root;
}private int findRootIndex(int[] inorder, int inBegin, int inEnd, int key) {for (int i = inBegin; i <= inEnd; i++) {if (inorder[i] == key) {return i;}}return -1;
}

10. 从中序与后序遍历序列构造二叉树

从中序与后序遍历序列构造二叉树

  • 创建根节点
  • 在中序遍历的字符串当中 找到当前根节点的下标
  • 分别创建右子树和左子树
public int postIndex;
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) {if (inBegin > inEnd) {return null;}// 1、创建根节点TreeNode root = new TreeNode(postorder[postIndex]);// 2. 在中序遍历的字符串当中 找到当前根节点的下标int rootIndex = findRootIndex(inorder, inBegin, inEnd, postorder[postIndex]);postIndex--;// F// 3. 分别创建右子树和左子树root.right = buildTreeChild(postorder, inorder, rootIndex + 1, inEnd);root.left = buildTreeChild(postorder, inorder, inBegin, rootIndex - 1);return root;
}private int findRootIndex(int[] inorder, int inBegin, int inEnd, int key) {for (int i = inBegin; i <= inEnd; i++) {if (inorder[i] == key) {return i;}}return -1;
}

11. 根据二叉树创建字符串

根据二叉树创建字符串

  • 判断根结点是否为空,当根结点不为空时(前序遍历)

  • 将根结点加入字符串中

  • 判断左结点

    • 如果根结点的左结点不为空

      • 加入"("
      • 构建左子树字符串
      • 加入")"
    • 如果根结点的左结点为空,但右节点不为空,需要将为空的左结点表示出来

      • 加入"()"
    • 如果左右结点均为空,无需操作

  • 判断右节点

    • 如果根结点的右结点不为空
      • 加入"("
      • 构建右子树字符串
      • 加入")"
public String tree2str(TreeNode root) {StringBuilder stringBuilder = new StringBuilder();tree2str2(root,stringBuilder);return stringBuilder.toString();
}private void tree2str2(TreeNode root, StringBuilder stringBuilder){if (root == null){return;}stringBuilder.append(root.val);if (root.left != null) {stringBuilder.append("(");tree2str2(root.left, stringBuilder);stringBuilder.append(")");}else if (root.right != null){stringBuilder.append("()");}else {}if (root.right != null){stringBuilder.append("(");tree2str2(root.right, stringBuilder);stringBuilder.append(")");}}

12. 二叉树的前序遍历非递归实现

二叉树的前序遍历非递归实现

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

13. 二叉树的中序遍历非递归实现

二叉树的中序遍历非递归实现

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

14. 二叉树的后续遍历非递归实现

二叉树的后续遍历非递归实现

public List<Integer> postorderTraversal(TreeNode root){List<Integer> list = new ArrayList<>();Stack<TreeNode> stack = new Stack<>();if (root == null){return list;}TreeNode cur = root;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){top = stack.pop();list.add(top.val);prev = top;}else {cur = top.right;}}return list;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/645617.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单快速取消AlertDialog的白色背景框,AlertDialog设置圆角背景

问题描述&#xff1a; 产品需求弹出的提示框是圆角&#xff0c;使用shape 设置圆角背景后&#xff0c;弹出的AlertDialog提示框四个角有白色的背景&#xff0c;据分析这个背景是 AlertDialog 父组件的背景色。 解决方法&#xff1a; 将Dialog的背景设置为透明色&#xff0c;代…

IDEA远程服务器开发

IDEA的远程开发是在本地去操远程服务器上的代码&#xff0c;可以直接将本地代码的编译,构建,调试,运行等工作都放在远程服务器上而本地运行一个客户端远程去操作服务器上的代码,就如同我们平常写代码一样。相比于云桌面成本更低,开发效率更高。 1.首先服务器配置jdk&#xff0…

第21课 在Android Native开发中架起java与c++互通的桥梁

在开始本节课&#xff0c;我尝试把项目拷贝到另一台电脑上以便继续工作&#xff0c;但出现了大量的“could not be resolved”问题&#xff0c;尝试包含新的include路径也无法解决该问题&#xff0c;最后删除了项目的Native Support&#xff0c;然后重新添加Native Support才解…

VI / VIM的使用

vi/vim 的区别简单点来说&#xff0c;它们都是多模式编辑器&#xff0c;不同的是 vim 是 vi 的升级版本&#xff0c;它不仅兼容 vi 的所有指令&#xff0c;而且 还有一些新的特性在里面。例如语法加亮&#xff0c;可视化操作不仅可以在终端运行&#xff0c;也可以运行于 x win…

k8s图形化管理工具rancher

Rancher和K8s的关系&#xff0c;Rancher和K8s区别对比。简单来说&#xff0c;K8s&#xff08;Kubernetes&#xff09;为企业提供了一种一致的方式来管理任何计算基础架构&#xff0c;Rancher则是用于管理位于任何位置的Kubernetes集群的完整平台。如果用户是自己手动部署K8s集群…

Industrial Props Pack - PBR

库中有几个令人难以置信的低多边形模型&#xff0c;具有PBR的高质量纹理。所有未来的免费更新。可以在城市或仓库中的射击游戏中使用的高质量模型。 下载&#xff1a; ​​Unity资源商店链接 资源下载链接 效果图&#xff1a;

C# Graphics对象学习

Graphics对象用于进行绘制&#xff1b; 从哪个对象获取的Graphics&#xff0c;然后进行绘制&#xff0c;就绘制到该对象上&#xff1b; 从位图获取Graphics&#xff0c;然后进行绘制&#xff0c;绘制到该位图上&#xff1b; 从某个控件获取Graphics&#xff0c;然后绘制&…

JavaScript 学习笔记(JS进阶 Day1)

「写在前面」 本文为 b 站黑马程序员 pink 老师 JavaScript 教程的学习笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。推荐先按顺序阅读往期内容&#xff1a; 1. JavaScript 学习笔记&#xff08;Day1&#xff09; 2. JavaSc…

MYSQL数据库详解(6)-- 视图存储方式触发器

MYSQL数据库详解&#xff08;6&#xff09; 视图特征&#xff1a;作用&#xff1a;创建视图使用视图删除视图 存储过程 ***为什么使用存储过程定义&#xff1a;存储过程和函数的区别缺陷&#xff1a;创建存储过程使用存储过程环境变量 局部环境变量 全局环境变量删除存储过程…

【linux】查看进程和子进程

在Linux系统中&#xff0c;可以使用多个命令来查看进程及其子进程。以下是一些常用的方法&#xff1a; 1. ps 命令 ps 命令用于显示当前进程的状态。可以结合不同的选项来查看进程及其子进程。 查看进程树&#xff1a; ps -auxf - -a 显示所有进程。 - -u 显示进程的用户/所…

上门服务小程序|预约上门服务系统开发有哪些功能?

在现代快节奏的生活中&#xff0c;压力和疲劳常常困扰着我们。为了缓解这种状况&#xff0c;越来越多的人选择去按摩店进行放松。然而&#xff0c;繁忙的工作和家庭责任往往让我们无法抽出时间去按摩店。在这种情况下&#xff0c;上门按摩服务应运而生。而随着科技的发展&#…

css实现右边边框分割线 渐变色,边框四角样式

分割线 代码 .data-item:first-of-type {border-right: 2px solid;border-image: linear-gradient(to top,rgba(0, 0, 0, 0.1) 0%,rgba(81, 110, 197, 0.76) 50%,rgba(0, 0, 0, 0.1) 100%)1;padding: 15px 0;}四角边框样式 代码 .chart-box {cursor: pointer;background: line…

Tomcat Notes: Web Security, HTTPS In Tomcat

This is a personal study notes of Apache Tomcat. Below are main reference material. - YouTube Apache Tomcat Full Tutorial&#xff0c;owed by Alpha Brains Courses. https://www.youtube.com/watch?vrElJIPRw5iM&t801s 1、Overview2、Two Levels Of Web Securi…

Linux浅学笔记02

目录 grep-wc-管道符 echo-tail-重定向符 vi编辑器 grep-wc-管道符 grep命令(过滤文件内容) //更准确的来说&#xff0c;是筛选包括“所需字符”的一句内容或多句内容。 语法&#xff1a;grep [-n] 关键字 文件路径 //-n&#xff1a;可选&#xff0c;表示在结果中匹配的行…

Vue2 - keep-alive 作用和原理

目录 1&#xff0c;介绍和作用2&#xff0c;原理3&#xff0c;使用场景3.1&#xff0c;效果展示3.2&#xff0c;实现思路 1&#xff0c;介绍和作用 <!-- 非活跃的组件将会被缓存&#xff01; --> <keep-alive><component :is"activeComponent" />…

【Golang入门教程】如何使用Goland创建并运行项目

自然语言处理的发展 文章目录 自然语言处理的发展**前言**创建新项目编辑运行/调试配置编写并运行代码总结强烈推荐专栏集锦写在最后 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站: 人工…

【边缘计算】TA的基本概念,以及TA的挑战和机遇

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读文章&#xff01; 此篇是【话题达人】序列文章&#xff0c;这一次的话题是《边缘计算的挑战和机遇》 文章将以博主的角度进行讲述&#xff0c;理解和水平有限&#xff0c;不足之处&#xff0c;望指正。 目录 背景基本概念挑战…

使用DBSyncer同步Oracle11g数据到Mysql5.7中_实现全量数据同步和增量数据实时同步_操作过程---数据同步之DBSyncer工作笔记007

之前都是用mysql和Postgresql之间进行同步的,已经实现了数据的实时同步,现在要实现Oracle数据库到Mysql数据库的全量,以及增量同步. 因为之前配置的不对,这里架构名写成了orcl,所以导致,虽然能连接上,但是,在进行数据同步的时候,看不到表,所以这里说一下如何进行连接 这里,首先…

socket以及字节序

1. socket 介绍&#xff1a; 简介&#xff1a; 所谓 socket&#xff08; 套接字&#xff09;&#xff0c;就是对网络中不同主机上的应用进程之间进行双向通信的 端点的抽象。 一个套接字就是网络上进程通信的一端&#xff0c;提供了应用层进程利用网络协议交换数据的机制。从所…

Vulnhub靶机:FunBox 5

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.15&#xff09; 靶机&#xff1a;FunBox 5&#xff08;10.0.2.30&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://www.vulnhub.com/entry/funb…