您的位置:首页 > 其它

二叉树基础题(六):树的子结构&二叉搜索树的判断&镜像二叉树

2020-06-29 04:13 302 查看

(尊重劳动成果,转载请注明出处:https://yangwenqiang.blog.csdn.net/article/details/105928523
冷血之心的博客)

这段时间完成了职业生涯第一次跳槽,对算法题目有了一个更深的认识和理解,这里将二叉树常见的面试题目以及解法补充完善。

二叉树基础题(一):先序遍历&中序遍历&后序遍历

二叉树基础题(二):分层遍历&二叉树深度&是否相同的树

二叉树基础题(三):完全二叉树的判断&平衡二叉树的判断

二叉树基础题(四):对称二叉树的判断&之字形分层遍历二叉树

二叉树基础题(五):二叉树的下一个节点&最低公共祖先节点

二叉树基础题(六):树的子结构&二叉搜索树的判断&镜像二叉树


今天我们再来看三道二叉树相关的基础题目吧,如下所示:

  • 树的子结构
  • 二叉搜索树
  • 镜像二叉树

题目一:树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

思路:
1、首先设置标志位result = false,因为一旦匹配成功result就设为true,剩下的代码不会执行,如果匹配不成功,默认返回false
2、递归思想,如果根节点相同则递归调用DoesTree1HaveTree2(),如果根节点不相同,则判断tree1的左子树和tree2是否相同,再判断右子树和tree2是否相同
3、注意null的条件,HasSubTree中,如果两棵树都不为空才进行判断,DoesTree1HasTree2中,如果Tree2为空,则说明第二棵树遍历完了,即匹配成功,tree1为空有两种情况:

  • 如果tree1为空&&tree2不为空说明不匹配,
  • 如果tree1为空,tree2为空,说明匹配。

代码实现如下:

public class Main {

public boolean HashSubtree(TreeNode root1, TreeNode root2){
boolean result = false;
//当Tree1和Tree2都不为null的时候,才进行比较。否则直接返回false
if(root1!=null&&root2!=null){
//如果找到了对应Tree2的根节点的点
if(root1.val==root2.val){
//以这个根节点为为起点判断是否包含Tree2
result = DoesTree1haveTree2(root1,root2);
}
//如果找不到,那么就再去root的左儿子当作起点,去判断时候包含Tree2
if(!result)
result = HashSubtree(root1.left, root2);
//如果还找不到,那么就再去root的右儿子当作起点,去判断时候包含Tree2
if(!result)
result = HashSubtree(root1.right, root2);
}
return result;
}
private boolean DoesTree1haveTree2(TreeNode root1, TreeNode root2) {
//如果Tree2已经遍历完了都能对应的上,返回true
if(root2==null)
return true;
//如果Tree2还没有遍历完,Tree1却遍历完了。返回false
if(root1==null&&root2!=null)
return false;
//如果其中有一个点没有对应上,返回false
if(root1.val!=root2.val)
return false;
//如果根节点对应的上,那么就分别去子节点里面匹配
return DoesTree1haveTree2(root1.left, root2.left)
&&DoesTree1haveTree2(root1.right, root2.right);
}
}
class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}

题目二:是否是二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

二叉搜索树的定义如下:

  • 节点的左子树只包含小于当前节点的数。
  • 节点的右子树只包含大于当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

看到这里,也许大家很easy就可以写出如下的错误代码

public boolean isValidBST(TreeNode root) {
if (root == null)
return true;
if (root.left != null && root.val <= root.left.val)
return false;
if (root.right != null && root.val >= root.right.val)
return false;

return isValidBST(root.left) && isValidBST(root.right);
}

这个代码有问题吗?有吗?当然有问题了。我们的当前节点的值要大于左边子树的所有节点,而不仅仅是其一个左子树节点,右边也是同样的道理。比如下边所示并不是一个合法的二叉搜索树,但是我们的算法会返回true


怎么办呢?

这个时候需要使用二叉树操作中经常需要使用的方法了,重载当前的函数,传入更多的参数,使得我们可以拥有更多的信息,最后才是递归调用!

正确的代码实现如下:

/**
* Definition for a binary tree node.
* public class TreeNode {
*     int val;
*     TreeNode left;
*     TreeNode right;
*     TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
return isValidBST(root,null,null);
}
// 使用辅助函数,增加函数参数列表,在参数中携带额外信息
private boolean isValidBST(TreeNode root, TreeNode min,TreeNode max){
if(root==null)
return true;
if(min!=null&&root.val<=min.val)
return false;
if(max!=null&&root.val>=max.val)
return false;

return isValidBST(root.left,min,root)&&isValidBST(root.right,root,max);
}
}

题目三:镜像二叉树(二叉树的翻转)

二叉树的镜像:操作给定的二叉树,将其变换为原二叉树的镜像。

思路:

这道题目还算比较简单吧,其实也挺难的,Homebrew 的作者Max Howell面试被 Google
拒啦,因为他不会翻转二叉树。是不是很悲剧?

这道题目可以给出两个解决方法:

  • 原地交换当前节点的左右节点
  • 新建一颗二叉树
class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;

public TreeNode(int val) {
this.val = val;

}

}

public class Solution {
// Mirror求出的即是当前二叉树的镜像
public void Mirror(TreeNode root) {
if (root == null)
return;
// 交换当前节点的左右节点
TreeNode tmpNode = root.left;
root.left = root.right;
root.right = tmpNode;

Mirror(root.left);
Mirror(root.right);
}

// 获取镜像二叉树(不改变原二叉树,重新生成了一个其镜像二叉树)
private  TreeNode getMirror(TreeNode pRoot) {
if (pRoot == null) {
return null;
}
TreeNode root = new TreeNode(pRoot.val);
root.right = getMirror(pRoot.left);
root.left = getMirror(pRoot.right);
return root;
}
}

总结:

二叉树相关的题目的一个技巧就是重载一个函数用来递归,可以传入额外的参数,获取更多的信息。另外就是二叉树的递归解法中,我们只要定义一个递归函数,并且处理好当前节点要处理的事情即可,别的都交给递归函数,认为其已经给我们解决了问题,切莫在脑子里进行压栈和出栈的操作,因为我们的脑子都不够用哈~

就比如说二叉树的镜像算法中,我们只需要确定下递归结束条件,处理好当前节点的事情(交换),然后再分别递归左右子树即可。

后续我会继续更新二叉树相关基础题目,感兴趣的同学可以持续关注交流~


注意啦,注意啦~

欢迎大家关注我的牛客专栏《Java开发岗面试题全解析》 ,点击图片查看详情。

Java开发岗高频面试题全解析,专栏共计32节,已经全部更新完毕。

专栏分9个模块来对Java岗位面试中的知识点进行解析,包括通用面试技能,Java基础,Java进阶,网络协议,常见框架以及算法,设计模式等。

专栏串点成面的解析每个面试题背后的技术原理,由浅入深,循序渐进,力争让大家掌握面试题目的背后的技术原理,摒弃背题模式的陋习。


如果对你有帮助,记得点赞哈,欢迎大家关注我的博客,关注公众号(文强的技术小屋),学习更多技术知识,一起遨游知识海洋~

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐