背景
整理一些有意思的题目,一些破题技巧与思想,均为学习笔记,做个记录…
说明
=> 五道 / 篇
=> Java
=> 二叉树相关
题目
1、重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
**思路:**首先得了解先序、中序的特点,接着从先序定位根,然后再去中序找出左右子树,依旧是递归实现。
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
return reConstructBinaryTree(pre, 0, pre.length - 1,
in, 0, in.length - 1);
}
/**
* @param pre 前序
* @param startPre 前序首位
* @param endPre 前序末位
* @param in 中序
* @param startIn 中序首位
* @param endIn 中序末位
* @return
*/
public TreeNode reConstructBinaryTree(int[] pre, int startPre, int endPre,
int[] in, int startIn, int endIn) {
// constraint
if (startPre > endPre || startIn > endIn) {
return null;
}
// 先序第一位即为根
TreeNode root = new TreeNode(pre[startPre]);
for (int i = startIn; i <= endIn; i++) {
// 中序找寻根所在位置
if (in[i] == pre[startPre]) {
/*
重点解析
1. startPre + i - startIn : 根据中序所找到的根,从而得知下一次递归的左子树,接着找到
前序的左子树部分,再次根据前序“根左右”的特性传入startPre 和 endPre,而由于startPre每次都在向
右,因此endPre应该根据startPre来决定
2. (startPre + i - startIn) + 1 :根据中序所找到的根,从而得知下一次递归的右子树,而上一步已
经在前序序列中分隔出根、左子树、右子树,那基本可以确定传入的数组下标
*/
root.left = reConstructBinaryTree(pre, startPre + 1, startPre + i - startIn,
in, startIn, i - 1);
root.right = reConstructBinaryTree(pre, (startPre + i - startIn) + 1, endPre,
in, i + 1, endIn);
}
}
return root;
}
private class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val) {
this.val = val;
}
}
2、树的子结构
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
**思路:**土方法,一个个比较,但是递归比较,以B树为参考系,从根开始匹配。
public boolean HasSubtree(TreeNode root1, TreeNode root2) {
boolean result = false;
if (root2 != null && root1 != null) {
// 如果找到了对应Tree2的根节点的点
if (root1.val == root2.val) {
result = doesTree1HaveTree2(root1, root2);
}
// 如果找不到,那么就再将root的左儿子当作起点,去判断时包含Tree2
if (!result) {
result = doesTree1HaveTree2(root1.left, root2);
}
// 如果还找不到,那么就再将root的右儿子当作起点,去判断时候包含Tree2
if (!result) {
result = HasSubtree(root1.right, root2);
}
}
return result;
}
public boolean doesTree1HaveTree2(TreeNode node1, TreeNode node2) {
/*
node1 和 node2 的为空判断务必得记住,一开始挺容易漏掉这个约束的!
*/
// 如果Tree2已经遍历完了都能对应得上,返回true
if (node2 == null) {
return true;
}
// 如果Tree2还没遍历完,Tree1却遍历完了。返回false
if (node1 == null) {
return false;
}
// 如果其中有一个点没有对应上,返回false
if (node1.val != node2.val) {
return false;
}
// 如果根节点对应的上,那么就分别去子节点里面匹配
return doesTree1HaveTree2(node1.left, node2.left) && doesTree1HaveTree2(node1.right, node2.right);
}
private class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
3、镜像二叉树
操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:
**思路:**递归交换左右节点
public void Mirror(TreeNode root) {
TreeNode tmp;
if (root != null) {
tmp = root.left;
root.left = root.right;
root.right = tmp;
if (root.left != null) {
Mirror(root.left);
}
if (root.right != null) {
Mirror(root.right);
}
}
}
private class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
4、打印二叉树
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
**思路:**先序的遍历打印方式,巧妙运用Queue实现,利用其“先进先出”的特点。
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
ArrayList<Integer> list = new ArrayList<>();
if (root == null) {
return list;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
/*
while循环主要针对的是queue是否为空,而queue实际存储的是每层的根节点,因此便可每层按顺序存进list
*/
while (!queue.isEmpty()) {
TreeNode treeNode = queue.poll();
if (treeNode.left != null) {
queue.offer(treeNode.left);
}
if (treeNode.right != null) {
queue.offer(treeNode.right);
}
list.add(treeNode.val);
}
return list;
}
private class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
5、二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
**思路:**首先得了解二叉搜索树(BST),接着递归判断是否满足BST的条件。
public boolean VerifySquenceOfBST(int[] sequence) {
if (sequence.length == 0) {
return false;
}
if (sequence.length == 1) {
return true;
}
return judge(sequence, 0, sequence.length - 1);
}
public boolean judge(int[] a, int start, int end) {
if (start > end) {
return true;
}
int i = start;
/*
找寻左右子树的分界点
*/
while (a[i] < a[end]) {
++i;
}
for (int j = i; j < end; j++) {
if (a[j] < a[end]) {
return false;
}
}
/*
递归,分出左右子树再次递归判断
*/
return judge(a, start, i - 1) && judge(a, i, end - 1);
}