剑指offer---树篇
JZ8 二叉树的下一个结点
题目地址
描述
给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针。下图为一棵有9个节点的二叉树。树中从父节点指向子节点的指针用实线表示,从子节点指向父节点的用虚线表示
示例:
输入:{8,6,10,5,7,9,11},8
返回:9
解析:这个组装传入的子树根节点,其实就是整颗树,中序遍历{5,6,7,8,9,10,11},根节点8的下一个节点就是9,应该返回{9,10,11},后台只打印子树的下一个节点,所以只会打印9,如下图,其实都有指向左右孩子的指针,还有指向父节点的指针,下图没有画出来
输入描述:
输入分为2段,第一段是整体的二叉树,第二段是给定二叉树节点的值,后台会将这2个参数组装为一个二叉树局部的子树传入到函数GetNext里面,用户得到的输入只有一个子树根节点
返回值描述:
返回传入的子树根节点的下一个节点,后台会打印输出这个节点
示例1
输入:
{8,6,10,5,7,9,11},8
返回值:
9
示例2
输入:
{8,6,10,5,7,9,11},6
返回值:
7
示例3
输入:
{1,2,#,#,3,#,4},4
返回值:
1
示例4
输入:
{5},5
返回值:
"null"
说明:
不存在,后台打印"null"
题目思路:
在中序遍历中,求一个结点的后继结点,对于所求结点node,分两种情况讨论:1.node的右子树存在。2.node的右子树不存在。
1. node的右子树存在
node结点的后继结点就是,node右子树的最左节点。
如下图所示:
3号结点的后继结点就是10号结点;
7号结点的后继结点就是9号结点。
2. node的右子树不存在
node结点的后继结点就是,需要向上寻找父节点,直到满足当前结点是父节点的左子节点。如果不存在满足以上条件的父节点,那么该结点没有后继节点。
如下图所示:
5号结点的后继结点 : 1号结点
10号结点的后继结点:8号结点
9号结点的后继节点 :无
代码:
/*
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){
return getMostLeft(pNode.right);
}else{
TreeLinkNode pre=pNode.next;//父节点
TreeLinkNode node=pNode;
while(pre!=null && pre.left!=node){
node=pre;
pre=pre.next;
}
return pre;
}
}
public TreeLinkNode getMostLeft(TreeLinkNode node){
TreeLinkNode res=node;
while(res.left!=null){
res=res.left;
}
return res;
}
}
JZ79 平衡二叉树
题目地址
描述
输入一棵节点数为 n 二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
样例解释:
样例二叉树如图,为一颗平衡二叉树
注:我们约定空树是平衡二叉树。
数据范围:n≤100,树上节点的val值满足 0≤val≤1000
要求:空间复杂度O(1),时间复杂度 O(n)
输入描述:
输入一棵二叉树的根节点
返回值描述:
输出一个布尔类型的值
示例1
输入:
{1,2,3,4,5,6,7}
返回值:
true
示例2
输入:
{}
返回值:
true
代码
一个二叉树的套路题,判断当前树是否是平衡二叉树,只需要知道它的左、右子树是否是平衡二叉树,以及左、右子树的高度信息来更新自己的状态。
import java.util.*;
public class Solution {
class Result{
int height;
boolean isBalanced;
Result(int height,boolean isBalanced){
this.height=height;
this.isBalanced=isBalanced;
}
}
public boolean IsBalanced_Solution(TreeNode root) {
if(root==null){
return true;
}
Result res=IsBalanced(root);
return res.isBalanced;
}
public Result IsBalanced(TreeNode root){
if(root==null){
return new Result(0,true);
}
Result left=IsBalanced(root.left);
Result right=IsBalanced(root.right);
int height = Math.max(left.height,right.height)+1;
boolean isBalanced = left.isBalanced && right.isBalanced && Math.abs(left.height-right.height)<=1;
return new Result(height,isBalanced);
}
}
JZ36 二叉搜索树与双向链表
题目地址
描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。如下图所示
数据范围:输入二叉树的节点数 0≤n≤1000,二叉树中每个节点的值 0≤val≤1000
要求:空间复杂度O(1)(即在原树上操作),时间复杂度 O(n)
注意:
1.要求不能创建任何新的结点,只能调整树中结点指针的指向。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继
2.返回链表中的第一个节点的指针
3.函数返回的TreeNode,有左右指针,其实可以看成一个双向链表的数据结构
4.你不用输出双向链表,程序会根据你的返回值自动打印输出
输入描述:
二叉树的根节点
返回值描述:
双向链表的其中一个头节点。
示例1
输入:
{10,6,14,4,8,12,16}
返回值:
From left to right are:4,6,8,10,12,14,16;From right to left are:16,14,12,10,8,6,4;
说明:
输入题面图中二叉树,输出的时候将双向链表的头节点返回即可。
示例2
输入:
{5,4,#,3,#,2,#,1}
返回值:
From left to right are:1,2,3,4,5;From right to left are:5,4,3,2,1;
说明:
5
/
4
/
3
/
2
/
1
树的形状如上图
代码
二叉搜索树中序遍历的结果是有序的,因此采用中序遍历的方式。
代码一是中序遍历的非递归形式,代码二是中序遍历的递归形式。
代码一
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 TreeNode Convert(TreeNode pRootOfTree) {
TreeNode res=null;
if(pRootOfTree==null){
return res;
}
TreeNode pre=null;
TreeNode root=pRootOfTree;
Stack<TreeNode> stack=new Stack<>();
while(!stack.isEmpty() || root!=null){
if(root!=null){
stack.add(root);
root=root.left;
}else{
root=stack.pop();
//...
//System.out.print(" "+root.val);
root.left=pre;
//给root的右指针赋值时,一定要注意右指针赋值后,不能影响往后的操作
//比如给右指针赋值为null,但是之后有用到右指针原来的值的话,会出问题滴
if(pre==null){
res=root;
}else{
pre.right=root;
}
pre=root;
root=root.right;
}
}
return res;
}
}
代码二
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
TreeNode pre=null;
TreeNode root=null;
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null){
return null;
}
//递归遍历左子树
Convert(pRootOfTree.left);
if(root==null){
root=pRootOfTree;//结果链表的头结点
}
//修改遍历的结点为双向链表
if(pre!=null){
pRootOfTree.left=pre;
pre.right=pRootOfTree;
}
//更新pre
pre=pRootOfTree;
//递归遍历右子树
Convert(pRootOfTree.right);
return root;
}
}