7.重建二叉树:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
解题思路:把重建二叉树分解为构建左右子树。根据题目给出的前序遍历、中序遍历数组,首先找出根节点 , 然后再根据中序遍历找到左子树和右子树的长度,分别构造出左右子树的前序遍历和中序遍历序列 ,最后分别对左右子树采取递归。
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(pre==null || in==null || pre.length !=in.length)//特殊情况
return null;
else
return reTree(pre,0,pre.length-1,in,0,in.length-1);
}
public TreeNode reTree(int [] pre,int stpre,int endpre,int [] in,int stin,int endin){
if(stpre>endpre || stin>endin)
return null;
int top = pre[stpre];
TreeNode root= new TreeNode(pre[stpre]);
for(int i=stin;i<=endin;i++){
if(in[i]== top){
root.left = reTree(pre,stpre+1,stpre-stin+i,in,stin,i-1);
root.right = reTree(pre,stpre-stin+i+1,endpre,in,i+1,endin);
}
}
return root;
}
}
8.二叉树的下一个结点:
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
解题思路:二叉树的下一个节点,一共有以下情况:1.二叉树为空,则返回空;2.节点右孩子存在,则设置一个指针从该节点的右孩子出发,一直沿着指向左子结点的指针找到的叶子节点即为下一个节点;3.节点不是根节点。如果该节点是其父节点的左孩子,则返回父节点;否则继续向上遍历其父节点的父节点,重复之前的判断,返回结果。
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode){
if(pNode == null)
return null;
if(pNode.right!=null){//该结点存在右孩子
pNode = pNode.right;
while(pNode.left!=null){
pNode = pNode.left;
}
return pNode;
}
while(pNode.next !=null){//不是根节点
if(pNode.next.left == pNode)//该结点是父结点的左孩子
return pNode.next;
else
pNode = pNode.next;
}
return null;
}
}
32.从上往下打印二叉树:
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
解题思路:从上到下打印二叉树的规律:每次打印一个结点时,将该结点的子节点放入到队列的末尾,从队首取出元素进行下一次判断,直至队列为空。(队列的类型可以为TreeNode,方便后续操作,同时,当二叉树根结点为空时,输出为空---注意位置!!!,放在开头会出现返回为[],而不是{})
import java.util.ArrayList;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
import java.util.*;
public class Solution {
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
ArrayList<Integer> result = new ArrayList<Integer>();
Queue<TreeNode> queue = new LinkedList<TreeNode>();
if(root == null)
return result;
queue.add(root);
while(queue.size()!=0){
TreeNode temp = queue.poll();
if(temp.left!=null )
queue.add(temp.left);
if(temp.right!=null )
queue.add(temp.right);
result.add(temp.val);
}
return result;
}
}
从上到下按层遍历二叉树,从本质上讲就是广度优先遍历二叉树。将起始结点放入到队列中,接下来,每次从队列的头部取出一个结点,遍历这个结点的子结点,依次放入到队列中,重复遍历直至所有结点都被遍历为止。
---->把二叉树打印成多行:
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
解题思路:按照上一题中从上到下打印二叉树的思路,在此基础上添加两个变量,用来记录下一行需要打印的个数,和该行未打印个数。特别注意的是,方法的返回类型要求,需要重新定义一个ArrayList,并在每次添加到result后清空原有数据。
import java.util.ArrayList;
import java.util.*;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<Integer> list = new ArrayList<Integer>();
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
Queue<TreeNode> queue = new LinkedList<TreeNode>();
if(pRoot == null)
return result;
int next = 0;//下一层要打印的个数
int remains = 1;//该层还没有打印的个数
queue.add(pRoot);
while(queue.size()!=0){
TreeNode temp = queue.poll();
if(temp.left!=null ){
queue.add(temp.left);
next++;
}
if(temp.right!=null ){
queue.add(temp.right);
next++;
}
list.add(temp.val);
remains--;
if(remains==0){
remains = next;
next = 0;
result.add(list);
list = new ArrayList<Integer>();
}
}
return result;
}
}
---->按之字形打印二叉树:
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
解题思路:按之字形打印二叉树,需要两个栈,当打印层是奇数层时,将子节点按照从左到右的顺序保存到第一个栈中,当打印层是偶数层时,将子节点按照从右到左的顺序保存到第一个栈中,当某一层的数据打印完成后,将两个栈交换,并继续打印下一层。
import java.util.ArrayList;
import java.util.*;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> list = new ArrayList<Integer>();
Stack<TreeNode> s1 = new Stack<TreeNode>();//存放偶数层
Stack<TreeNode> s2 = new Stack<TreeNode>();//存放奇数层
int next=0,remains = 1,level=1;//下一层,这一层剩余结点,层数
if( pRoot == null)
return result;
s1.push(pRoot);
while(s1.size()!=0 || s2.size()!=0){
if(level%2!=0){
if(s1.size()!=0){
TreeNode temp = s1.pop();
if(temp.left!=null){
s2.push(temp.left);
next++;
}
if(temp.right!=null){
s2.push(temp.right);
next++;
}
list.add(temp.val);
remains--;
}
}else{
if(s2.size()!=0){
TreeNode temp = s2.pop();
if(temp.right!=null){
s1.push(temp.right);
next++;
}
if(temp.left!=null){
s1.push(temp.left);
next++;
}
list.add(temp.val);
remains--;
}
}
if(remains==0){
remains = next;
next=0;
level++;
result.add(list);
list = new ArrayList<Integer>();
}
}
return result;
}
}
55.二叉树的深度:
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
解题思路:采用递归的方式实现,树的深度为左右子树中深度较大的值+1。
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public int TreeDepth(TreeNode root) {
if(root==null)
return 0;
int ldeepth = TreeDepth(root.left);
int rdeepth = TreeDepth(root.right);
if(ldeepth>=rdeepth)
return ldeepth+1;
else
return rdeepth+1;
}
}
---->平衡二叉树:
输入一棵二叉树,判断该二叉树是否是平衡二叉树。如果某二叉树中任意结点的左右子树的深度相差不超过1,即为平衡二叉树。
解题思路:遍历每个结点时,调用上一题中求解二叉树深度的方法,判断每个结点的深度差。
public class Solution {
public int TreeDepth(TreeNode root) {
if(root==null)
return 0;
int ldeepth = TreeDepth(root.left);
int rdeepth = TreeDepth(root.right);
if(ldeepth>=rdeepth)
return ldeepth+1;
else
return rdeepth+1;
}
public boolean IsBalanced_Solution(TreeNode root) {
if(root==null)
return true;
int left = TreeDepth(root.left);
int right = TreeDepth(root.right);
int dif = left-right;
if(dif>1 || dif<-1)
return false;
return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
}
}
33.二叉搜索树的后序遍历序列:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
解题思路:二叉搜索树的左子树总比根结点小,右子树比根结点大。采用递归方式。Arrays.copyOfRange(T[ ] original,int from,int to),将一个原始的数组original,从小标from开始复制,复制到小标to,生成一个新的数组,包括下标from,不包括下标to。
import java.util.Arrays;
public class Solution {
public boolean VerifySquenceOfBST(int [] sequence) {
if(sequence==null||sequence.length==0)
return false;
int root = sequence[sequence.length-1];
int i=0;
for(;i<sequence.length-1;i++){
if(sequence[i]>root)
break;
}
int j = i;
for(;j<sequence.length-1;j++){
if(sequence[j]<root)
return false;
}
boolean resultl =true;
boolean resultr = true;
if(i > 0)
resultl = VerifySquenceOfBST(Arrays.copyOfRange(sequence,0, i));
if(i <sequence.length-1)
resultr = VerifySquenceOfBST(Arrays.copyOfRange(sequence,i, sequence.length-1));
return (resultl && resultr) ;
}
}
54.二叉搜索树的第K个结点:
给定一颗二叉搜索树,请找出其中的第k大的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。
解题思路:利用中序遍历算法即可。
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
//中序遍历
int index = 0;
TreeNode KthNode(TreeNode pRoot, int k){
TreeNode target = null;
if(pRoot!=null){
if(pRoot.left!=null)
target = KthNode(pRoot.left,k);
if(target!=null)
return target;
//左子树中没有
index++;
if(index==k)
return pRoot;
target = KthNode(pRoot.right,k);
if(target!=null)
return target;
}
return null;
}
}
37.序列化二叉树:
请实现两个函数,分别用来序列化和反序列化二叉树。
解题思路:前序遍历是从根结点开始,可以用来序列化二叉树。序列化与反序列化的过程采用递归的方式。把二叉树分为根结点、左子树、右子树。
对于序列化:使用前序遍历,递归的将二叉树的值转化为字符,并且在每次二叉树的结点不为空时,在转化val所得的字符之后添加一个' , '作为分割。对于空节点则以 '%' 代替。
对于反序列化:按照前序顺序,递归的使用字符串中的字符创建一个二叉树,递归函数的参数为string ,通过索引的变化保证字符串的逐渐移动。
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
int index=-1;
String Serialize(TreeNode root) {
StringBuilder str = new StringBuilder();
Serialize2(root , str);
return str.toString();
}
public void Serialize2(TreeNode root , StringBuilder str){
if(root == null)
str.append("%,");
else{
str.append(root.val + ",");
Serialize2(root.left , str);
Serialize2(root.right , str);
}
}
TreeNode Deserialize(String str) {
if(str =="" )
return null;
String[] ser = str.split(",");
return Deserialize(ser);
}
public TreeNode Deserialize(String[] str) {
index++;
while(!str[index].equals("%")){
TreeNode root = new TreeNode(Integer.parseInt(str[index]));
root.left = Deserialize(str);
root.right = Deserialize(str);
return root;
}
return null;
}
}
27.二叉树的镜像:
操作给定的二叉树,将其变换为源二叉树的镜像。
解题思路:二叉树的镜像即把每个结点的左右结点交换,采用递归方式。
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public void Mirror(TreeNode root) {
if(root == null)
return;
if(root.left == null && root.right == null)
return ;
TreeNode temp = root.right;
root.right = root.left;
root.left = temp;
if(root.left!=null)
Mirror(root.left);
if(root.right!=null)
Mirror(root.right);
}
}
28.对称的二叉树:
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
解题思路:对特殊情况进行处理后,按照左子树的左子树和右子树的右子树相同,左子树的右子树和右子树的左子树相同即可,采用递归。
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
boolean isSymmetrical(TreeNode pRoot){
return Symmetrical(pRoot,pRoot);
}
boolean Symmetrical(TreeNode root1,TreeNode root2){
if(root1 == null && root2==null)
return true;
if(root1 == null || root2==null)
return false;
if(root1.val != root2.val)
return false;
return Symmetrical(root1.left,root2.right)
&& Symmetrical(root1.right,root2.left);
}
}
26.树的子结构:
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
解题思路:采用递归的方式,先找到树A中与树B根结点相同的结点,然后开始判断树A树B 的左右子树是否相同。注意空指针的特殊情况。
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public boolean IsSubtree(TreeNode root1,TreeNode root2) {
if(root1==null && root2!=null )
return false;
if(root2==null)
return true;
if(root1.val != root2.val)
return false;
return IsSubtree(root1.left,root2.left) && IsSubtree(root1.right,root2.right);
}
public boolean HasSubtree(TreeNode root1,TreeNode root2){
boolean result = false;
if(root1 != null && root2 != null){
if(root1.val == root2.val){
result = IsSubtree(root1,root2);
}
if(!result){result = HasSubtree(root1.left, root2);}
if(!result){result = HasSubtree(root1.right, root2);}
}
return result;
}
}