OptimalSolution(2)--二叉树问题(4)子树与拓扑结构
一、判断t1树是否包含t2树全部的拓扑结构
- 1
- / \
- 2 3 2
- / \ / \ / \
- 4 5 6 7 4 5
- / \ / /
- 8 9 10 8 返回:true
解法(O(M×N)):如果t1中某棵子树头结点和t2头结点的值一样,则从这两个头结点开始匹配,匹配的每一步都是让t1上的节点跟着t2的先序遍历移动,每移动一步,都检查t1的当前节点和t2当前节点的值是否一样。如果匹配的过程中发现有不匹配的过程,直接返回false,那么再去寻找t1的下一棵树。
- public boolean contains(Node t1, Node t2) {
- return check(t1, t2) || contains(t1.left, t2) || contains(t1.right, t2);
- }
- private boolean check(Node h, Node t2) {
- if (t2 == null) return true;
- if (h == null || h.val != t2.val) return false;
- return check(h.left, t2.left) && check(h.right, t2.right);
- }
二、判断t1树中是否有与t2树拓扑结构完全相同的子树
- 1
- / \
- 2 3 2 2
- / \ / \ / \ / \
- 4 5 6 7 4 5 4 5
- \ / \ / \
- 8 9 8 9 返回:true 8 返回:false
如果t1的节点数为N,t2的节点数为M
1.时间复杂度为O(N×M)的方法:对于t1的每棵子树,都去判断是否与t2树的拓扑结构完全一样,这个过程的复杂度为O(M),t1的子树一共有N棵,所以时间复杂度是O(N×M)
做法:(知识扩展:判断两棵树是否相等)首先定义一个判断两棵树是否相等的方法,然后让s的每一个子树都和t作比较,看是否两棵树相等,如果存在相等,那么就返回true
- public boolean isSubtree(TreeNode s, TreeNode t) {
- if (s == null) return false;
- if (isSame(s, t)) return true;
- return isSubtree(s.left, t) || isSubtree(s.right, t);
- }
- private boolean isSame(TreeNode sub, TreeNode t) {
- if (sub == null && t == null) return true;
- if (sub != null && t != null) {
- if (sub.val == t.val) {
- if (isSame(sub.left, t.left)) {
- if (isSame(sub.right, t.right)) {
- return true;
- }
- }
- }
- }
- return false;
- }
2.时间复杂度为O(N+M)的方法:先将t1树前序遍历序列化成字符串“1!2!4!#!8!#!#!5!9!#!#!#!#!3!6!#!#!7!#!#!”,而t2树前序遍历序列化为字符串“2!4!#!8!#!#!5!9!#!#!”(t3树前序遍历序列化为字符串“2!4!#!8!#!#!5!#!#!”),也就是验证t2str是否是t1str的子串即可,可以用KMP算法在线性时间内解决。所以t1序列化的时间复杂度为O(N),t2序列化的时间复杂度是O(M),KMP解决两个字符串的匹配问题O(M+N),所以时间复杂度是O(M+N)。
三、判断一棵树是否为镜像
- 1
- / \
- 2 2
- / \ / \
- 3 4 4 3 true
- 1
- / \
- 2 2
- \ \
- 3 3 false
思路很关键:将一棵树分成两棵树判断。
解法:如果两棵树为镜像树,那么必须满足:(1)这两棵树的根节点的值相同(2)第一棵树的左子树是第二棵树的右子树(3)第一棵树的右子树是第一棵树的左子树
1.递归
- public boolean isSymmetric(TreeNode root) {
- return isSymmetircTwoTrees(root, root);
- }
- private boolean isSymmetircTwoTrees(TreeNode t1, TreeNode t2) {
- if (t1 == null && t2 == null) return true;
- if (t1 == null || t2 == null) return false;
- return t1.val == t2.val && isSymmetircTwoTrees(t1.left, t2.right) && isSymmetircTwoTrees(t1.right, t2.left);
- }
2.迭代(BFS)
- public boolean isSymmetricBFS(TreeNode root) {
- if (root == null) return true;
- Queue<TreeNode> queue = new LinkedList<>();
- queue.offer(root);
- queue.offer(root);
- while (!queue.isEmpty()) {
- TreeNode t1 = queue.poll();
- TreeNode t2 = queue.poll();
- if (t1 == null && t2 == null) continue;
- if (t1 == null || t2 == null) return false;
- if (t1.val != t2.val) return false;
- queue.offer(t1.left);
- queue.offer(t2.right);
- queue.offer(t1.right);
- queue.offer(t2.left);
- }
- return true;
- }
四、二叉树的反转(考虑问题太过复杂,要从最基本的要求开始考虑)
1.仅仅适用于完全二叉树的反转(不满足某个节点有且仅有一个子树为空的情况)
- 4
- / \
- 2 7
- / \ / \
- 1 3 6 9
- Output:
- 4
- / \
- 7 2
- / \ / \
- 9 6 3 1
代码实现:
- public TreeNode invertTree(TreeNode root) {
- if (root != null) {
- Queue<TreeNode> queue = new LinkedList<>();
- queue.offer(root.left);
- queue.offer(root.right);
- while (!queue.isEmpty()) {
- TreeNode t1 = queue.poll();
- TreeNode t2 = queue.poll();
- if (t1 == null && t2 == null) continue;
- if (t1 != null && t2 != null) {
- int tmp1 = t1.val;
- t1.val = t2.val;
- t2.val = tmp1;
- }
- queue.offer(t1.left);
- queue.offer(t2.right);
- queue.offer(t1.right);
- queue.offer(t2.left);
- }
- }
- return root;
- }
2.适用于所有二叉树的反转
- 1 1
- / \
- 2 2
思路1:基于最简单的层序遍历, TreeNode tmp = root.left; root.left = root.right; root.right = tmp;如上面的测试用例,如果root=1,root.left=2,root.right=null,那么在交换之后,还是可以满足,即root.left=null,root.right=2
还要注意的是:必须使用TreeNode cur = queue.poll();作为引用,不能直接使用root = queue.poll();,如果直接使用root,return的是最后一个遍历到的节点。
- public TreeNode invertTreeBFS(TreeNode root) {
- if (root != null) {
- Queue<TreeNode> queue = new LinkedList<>();
- queue.offer(root);
- while(!queue.isEmpty()) {
- TreeNode cur = queue.poll();
- TreeNode tmp = cur.left;
- cur.left = cur.right;
- cur.right = tmp;
- if (cur.left != null) queue.offer(cur.left);
- if (cur.right != null) queue.offer(cur.right);
- }
- }
- return root;
- }
思路2:基于最简单的后序递归遍历,即invertTreeDFS方法返回root的反转,而root的左子树是右子树的反转,并且root的右子树是左子树的反转。
- public TreeNode invertTreeDFS(TreeNode root) {
- if (root == null) return null;
- TreeNode right = invertTree(root.right);
- TreeNode left = invertTree(root.left);
- root.left = right;
- root.right = left;
- return root;
- }
OptimalSolution(2)--二叉树问题(4)子树与拓扑结构的更多相关文章
- OptimalSolution(2)--二叉树问题(3)Path路径问题
一.在二叉树中找到累加和为指定值的最长路径长度 给定一棵二叉树和一个32位整数sum,求累加和为sum的最长路径长度.路径是指从某个节点往下,每次最多选择一个孩子节点或者不选所形成的节点链 -3 / ...
- OptimalSolution(2)--二叉树问题(2)BST、BBT、BSBT
一.判断二叉树是否为平衡二叉树(时间复杂度O(N)) 平衡二叉树就是:要么是一棵空树,要么任何一个节点的左右子树高度差的绝对值不超过1. 解法:整个过程为二叉树的后序遍历.对任何一个节点node来说, ...
- OptimalSolution(2)--二叉树问题(1)遍历与查找问题
一.二叉树的按层打印与ZigZag打印 1.按层打印: 1 Level 1 : 1 / \ 2 3 Level 2 : 2 3 / / \ 4 5 6 Level 3 : 4 5 6 / \ 7 8 ...
- ZOJ3805Machine(二叉树左右子树变换)
/* 题意:建立一棵二叉树,左子树和父节点占一个宽度,右子树另外占一个宽度! 使任意左右子树交换顺序,使得整个树的宽度最小! 思路:递归交换左右子树 ! 开始写的代码复杂了,其实左右子树不用真的交换, ...
- 99 Lisp Problems 二叉树(P54~P69)
P54A (*) Check whether a given term represents a binary tree Write a predicate istree which returns ...
- 记忆化搜索 codevs 2241 排序二叉树
codevs 2241 排序二叉树 ★ 输入文件:bstree.in 输出文件:bstree.out 简单对比时间限制:1 s 内存限制:128 MB [问题描述] 一个边长为n的正三 ...
- 二叉树-你必须要懂!(二叉树相关算法实现-iOS)
这几天详细了解了下二叉树的相关算法,原因是看了唐boy的一篇博客(你会翻转二叉树吗?),还有一篇关于百度的校园招聘面试经历,深刻体会到二叉树的重要性.于是乎,从网上收集并整理了一些关于二叉树的资料,及 ...
- POJ2255二叉树
题目大意就是给出你一个二叉树的前序和中序,要你求后序. 思路:二叉树的排序就是根据根节点的位置来定义的.所以找到二叉树的根节点是最重要的,二叉树的左子树和右子树也可以看成是二叉树,以此递归: #inc ...
- 【数据结构】之二叉树的java实现
转自:http://blog.csdn.net/wuwenxiang91322/article/details/12231657 二叉树的定义: 二叉树是树形结构的一个重要类型.许多实际问题抽象出来的 ...
随机推荐
- IDEA新建一个多maven模块工程(有图)
对于一些大型的项目来说,将项目的各个模块理清并进行管理,便于后续项目的维护,使用maven管理是很方便的,它可以很好的构建模块来设计项目的整体结构,对一些小型的项目不建议使用 1.新建父maven模块 ...
- SpringBoot导入jsp依赖始终报错
先粘出我自己的pom代码: <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&qu ...
- 2019 中国.NET 开发者峰会正式启动
2014年微软组织并成立.NET基金会,微软在成为主要的开源参与者的道路上又前进了一步.2014年以来已经有众多知名公司加入.NET基金会,Google,微软,AWS三大云厂商已经齐聚.NET基金会, ...
- FFmpeg(四) 像素转换相关函数理解
一.基本流程 1.sws_getCachedContext();//得到像素转换的上下文 2.sws_scale()://进行转换 二.函数说明 1.SwsContext *vctx = NULL; ...
- 【Java】 生成32位随机字符编号
/** * 生成32位编码 * @return string */ public static String getUUID(){ String uuid = UUID.randomUUID().to ...
- css3:bacground-size
个人博客: https://chenjiahao.xyz CSS3之背景尺寸Background-size是CSS3中新加的一个有关背景的属性,这个属性是改变背景尺寸的通过各种不同是属性值改变背景尺寸 ...
- Rust入坑指南:坑主驾到
欢迎大家和我一起入坑Rust,以后我就是坑主,我主要负责在前面挖坑,各位可以在上面看,有手痒的也可以和我一起挖.这个坑到底有多深?我也不知道,我是抱着有多深就挖多深的心态来的,下面我先跳了,各位请随意 ...
- springmvc引入静态资源文件
如果web.xml中配置的DispatcherServlet请求映射为“/”, springmvc将捕获web容器所有的请求,当然也包括对静态资源的请求.springmvc会将他们当成一个普通请求处理 ...
- 从xxe-lab来深入学习xxe漏洞
这几天,想复习一下xxe的知识,于是把以前的一个靶场拿过来玩玩,顺便审计一下代码2333,靶场地址:https://github.com/c0ny1/xxe-lab 首先先练习的是php-xxe: 我 ...
- 记录一次jvm内存泄露的问题
前些天,运维告诉我刚上线的java服务占用CPU过高. 以下是发现解决问题的具体流程. 1:通过#top命令查看,我的java服务确实把CPU几乎占满了,如图 可看到18400这个进程CPU占用达到了 ...