描述
给定一个二叉树的根节点root,返回它的中序遍历结果。
数据范围:树上节点数满足0≤n≤1000,树上每个节点的值满足 0≤val≤1000
进阶:空间复杂度 O(n),时间复杂度 O(n)
示例1
输入:
{1,2,#,#,3} 返回值: [2,3,1] 说明:
示例2
输入:
{}
返回值:
[]
示例3
输入:
{1,2}
返回值:
[2,1]
说明:
0原始的中序遍历模块
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*
* C语言声明定义全局变量请加上static,防止重复定义
*/
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @return int整型一维数组
* @return int* returnSize 返回数组行数
*/
void dfs(struct TreeNode*root,int *a,int* returnSize){
if(root==NULL){
return;
}
dfs(root->left,a,returnSize);
a[(*returnSize)++]=root->val;
dfs(root->right,a,returnSize);
}
int* inorderTraversal(struct TreeNode* root, int* returnSize ) {
// write code here
int* a=(int*)malloc(sizeof(int)*1000);
*returnSize=0;
dfs(root, a, returnSize);
return a;
}
1. 二叉搜索树与双向链表(中序遍历的变形)
描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。如下图所示
数据范围:输入二叉树的节点数 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;
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
看起来复杂,其实就是中序遍历对访问节点进行一个修改左右指针
1.使用二叉树的中序遍历可以获得一个要求链表结点的访问顺序;
2.在这个顺序中,我们要存储当前的结点root和访问前的结点pre(pre的值一定是比root小的)
3.判断当前节点的左驱节点是否存在?
如果不存在,则(当前节点为最左边的节点)head=root (双链表的头指针)
如果存在, 修改pre和cur的左右指向,pre.right = root; root.left = pre;
4.更新左驱节点 pre=root (将当前的节点变为下一个节点的左驱节点)
/**
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 head=null; //初始化双链表的头结点
void inorder(TreeNode root){
if(root==null) return ;
inorder(root.left); //左递归
if(pre==null){ //如果该节点没有左驱节点则说明该节点是第一个节点
head=root; //作为双链表的头指针
}
else{
pre.right=root; //左驱节点的右指针指向当前节点
root.left=pre; //当前节点的左指针指向左驱节点
}
pre=root; //更新左驱节点,将当前的节点变为左驱节点
inorder(root.right); //右递归
}
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null){
return pRootOfTree;
}
inorder(pRootOfTree);
return head;
}
}
2.BM34 判断是不是二叉搜索树(中序遍历)
描述
给定一个二叉树根节点,请你判断这棵树是不是二叉搜索树。
二叉搜索树满足每个节点的左子树上的所有节点均小于当前节点且右子树上的所有节点均大于当前节点。
例:
上图1
上图2
数据范围:节点数量满足\1≤n≤10^4 ,节点上的值满足 −2^31≤val≤2^31−1
示例1
输入:
{1,2,3}
返回值:
false
说明:
如题面图1
示例2
输入:
{2,1,3}
返回值:
true
说明:
如题面图2
法一:可以递归中序遍历判断左右每个子树是否是二叉搜索树
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 {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @return bool布尔型
*/
int pre=Integer.MIN_VALUE;
public boolean isValidBST (TreeNode root) {
if(root==null){
return true;
}
if(!isValidBST(root.left)){ //遍历左子树,判断左子树是否是二叉搜索树
return false;
}
if(pre>root.val){ //根节点的处理
return false;
}else{
pre=root.val; //上一个节点的值更新,这个值始终是当前节点的上一个节点的值
}
if(!isValidBST(root.right)){ //遍历右子树,判断右子树是否是二叉搜索树
return false;
}
return true; //是二叉搜索树
//return isValidBST(root.right); //上述的遍历右子树也可以直接这样返回遍历左子树,判断左子树是否是二叉搜索树
}
}
法二:非递归中序遍历的方式(原理跟递归中序一样)
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 {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @return bool布尔型
*/
public boolean isValidBST (TreeNode root) {
if(root.left==null&&root.right==null)
return true;
Stack<TreeNode> st=new Stack<>();
TreeNode p=root;
int pre=Integer.MIN_VALUE; //定义最小值
while(!st.isEmpty()||p!=null){ //栈实现中序遍历
while(p!=null){
st.push(p); //不停的进栈
p=p.left; //不停访问左节点子树
}
//当左节点为空,则表示已经到了最左节点,此时p=null
//出栈
p=st.pop();
if(p.val<pre){
return false;
}
pre=p.val; //更改上一个节点的值
p=p.right; //遍历右子树
}
return true;
}
}
法三:递归
思路:
每个节点的值都满足一个区间范围。
初始化,根节点的范围 int 的范围。
如果当前节点的值小于左区间或者大于右区间,则返回 false。
否则,继续分别递归左右儿子节点:
递归左儿子,并将左儿子的右区间修改为父节点的值;
递归右儿子,并将右儿子的左区间修改为父节点的值。
最后,如果没有返回false,说明满足二叉搜索树,返回true。
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 {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @return bool布尔型
*/
public boolean dfs(TreeNode root,int l,int r){
if(root==null){
return true;
}
if(root.val<l||root.val>r){
return false;
}
return dfs(root.left,l,root.val)&&dfs(root.right,root.val,r);
}
int pre=Integer.MIN_VALUE;
public boolean isValidBST (TreeNode root) {
int INT_MIN=Integer.MIN_VALUE; //区间最小值
int INT_MAX=Integer.MAX_VALUE; //区间最大值
if(root==null)
return true;
return dfs(root,INT_MIN,INT_MAX);//根节点的区间范围为int的范围
}
}