一、判断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)子树与拓扑结构的更多相关文章

  1. OptimalSolution(2)--二叉树问题(3)Path路径问题

    一.在二叉树中找到累加和为指定值的最长路径长度 给定一棵二叉树和一个32位整数sum,求累加和为sum的最长路径长度.路径是指从某个节点往下,每次最多选择一个孩子节点或者不选所形成的节点链 -3 / ...

  2. OptimalSolution(2)--二叉树问题(2)BST、BBT、BSBT

    一.判断二叉树是否为平衡二叉树(时间复杂度O(N)) 平衡二叉树就是:要么是一棵空树,要么任何一个节点的左右子树高度差的绝对值不超过1. 解法:整个过程为二叉树的后序遍历.对任何一个节点node来说, ...

  3. 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 ...

  4. ZOJ3805Machine(二叉树左右子树变换)

    /* 题意:建立一棵二叉树,左子树和父节点占一个宽度,右子树另外占一个宽度! 使任意左右子树交换顺序,使得整个树的宽度最小! 思路:递归交换左右子树 ! 开始写的代码复杂了,其实左右子树不用真的交换, ...

  5. 99 Lisp Problems 二叉树(P54~P69)

    P54A (*) Check whether a given term represents a binary tree Write a predicate istree which returns ...

  6. 记忆化搜索 codevs 2241 排序二叉树

    codevs 2241 排序二叉树 ★   输入文件:bstree.in   输出文件:bstree.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] 一个边长为n的正三 ...

  7. 二叉树-你必须要懂!(二叉树相关算法实现-iOS)

    这几天详细了解了下二叉树的相关算法,原因是看了唐boy的一篇博客(你会翻转二叉树吗?),还有一篇关于百度的校园招聘面试经历,深刻体会到二叉树的重要性.于是乎,从网上收集并整理了一些关于二叉树的资料,及 ...

  8. POJ2255二叉树

    题目大意就是给出你一个二叉树的前序和中序,要你求后序. 思路:二叉树的排序就是根据根节点的位置来定义的.所以找到二叉树的根节点是最重要的,二叉树的左子树和右子树也可以看成是二叉树,以此递归: #inc ...

  9. 【数据结构】之二叉树的java实现

    转自:http://blog.csdn.net/wuwenxiang91322/article/details/12231657 二叉树的定义: 二叉树是树形结构的一个重要类型.许多实际问题抽象出来的 ...

随机推荐

  1. java自学小段 产生随机数

    public class Suijishu { public static void main(String[] args) { double i=Math.random();//产生一个0-0.5的 ...

  2. python库之turtle(图形绘制) 开启新的快乐源泉

    相信有不少人学习python 都是听了老前辈的推荐 “学python好,python有趣的代码多” 比如说画一只小狮子 这就是今天想要介绍的绘制图形库-turtle 如果也想这样画一只小狮子,或者其他 ...

  3. Python2与Python3的map()

    1. map()函数 Python2中,map(func, seq1[,seq2[...[,seqn)将func作用于seq*的每个序列的索引相同的元素,并最终生成一个[func(seq1[0], s ...

  4. Cisco交换机、路由器,密码恢复

    一.路由器密码恢复 1.重启路由器,同时按下ctrl + breack键中断IOS的加载,路由器进入ROM Monitor模式 2.将配置寄存器的值更改为 0x2142,表示在启动时忽略startup ...

  5. Centos6 日常使用小结

    网络配置目录 1./etc/sysconfig/network-script/ifcfg-eth0 2.netstat -rn Kernel IP routing table Destination ...

  6. [JavaScript] 《JavaScript高级程序设计》笔记

    1.||   和 && 这两个逻辑运算符和c#是类似的,都是惰性的计算 a() || b()  若a()为真返回a()的结果,此时b()不计算: a()为假则返回b() a() &am ...

  7. Axure实现百度登录页面(一)

    本文主要实现了百度登录页面的设计,其中最主要的是实现点击用户名和密码框时使边框颜色发生变化 (1)首先拖入一个矩形框,将边框可见性全部去掉 (2)将百度的图片拖入,将“用户名密码登录”和“短信快捷登录 ...

  8. 通过实例理解Java网络IO模型

    网络IO模型及分类 网络IO模型是一个经常被提到的问题,不同的书或者博客说法可能都不一样,所以没必要死抠字眼,关键在于理解. Socket连接 不管是什么模型,所使用的socket连接都是一样的. 以 ...

  9. 推荐一款超好用的工具cmder

    今天来推荐一个超级好用的命令行工具:cmder 一款Windows环境下非常简洁美观易用的cmd替代者,它支持了大部分的Linux命令.支持ssh连接linux,使用起来非常方便.比起cmd.powe ...

  10. bs4 UnicodeEncodeError: 'gbk' codec can't encode character '\xa0'

    Problem: 写爬虫时,出现了以下错误: 意思是Unicode编码错误,gbk编解码器不能编码\xa0字符. 爬取信息包含中文,使用BeautifulSoup库解析网页,用get_text()方法 ...