二叉搜索树判定

题目描述

   给定一个二叉树,判断其是否是一个有效的二叉搜索树。假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

输入描述

   第一行两个数n,root,分别表示二叉树有n个节点,第root个节点是二叉树的根。
   接下来共n行,第i行三个数val_i,left_i,right_i,
分别表示第i个节点的值val是val_i,左儿子left是第left_i个节点,右儿子right是第right_i个节点,节点0表示空。1<=n<=100000,保证是合法的二叉树。

输出描述

   输出"true"如果给定二叉树是二叉搜索树,否则输出"false"。

解题思路

   基本思路:想要一棵二叉树是二叉搜索树只要保证左右子树都是耳茶搜索树并且左子树的所有节点都小于根节点,右子树的所有节点都大于根节点,递归是关键。
   方法一:对每一个节点,将其与左右子树的所有节点进行比较,时间复杂度O(N^2)。
   方法二:对于根节点,判断其左右子树是否为二叉搜索树,若满足条件,找到左子树中的最大元素,以及右子树中的最小元素,当根节点元素的值大于左子树的最大元素及小于右子树的最小元素,则可以确定该二叉树为二叉搜索树。平均时间复杂度T(N)=T(N/2)+O(logN),为O(NlogN)。
   方法三:对于方法二来说,递归判断左右子树是否为二叉搜索树后再在左右子树中寻找最大最小元素,是有冗余操作的,因此考虑合并两者,将判断二叉搜索树回归到以元素范围进行判断上,对于一棵二叉树,找到左右子树的元素范围,然后判断根元素是否在两个范围的并集内,如果不在,就不是二叉搜索树。由于整棵二叉搜索树的范围是由左右子树范围合并而成,只需要对整棵树进行递归即可。平均时间复杂度T(N)=2T(N/2)+O(1),为O(logN)。
二叉树范围寻找

代码实现

方法二

class Solution{
	public:
	bool CompareRight(TreeNode* root,int value){
		if(root==NULL)return true;
		TreeNode* current=root;
		int val;
		while(true){
			val=current->val;
			if(current->left!=NULL)
				current=current->left;
			else if(current->right!=NULL)
				current=current->right;
			else
				break;
		}
		return val>value;
	}
	bool CompareLeft(TreeNode* root,int value){
		if(root==NULL)return true;
		TreeNode* current=root;
		int val;
		while(true){
			val=current->val;
			if(current->right!=NULL)
				current=current->right;
			else if(current->left!=NULL)
				current=current->left;
			else
				break;
		}
		return val<value;
	}
	bool IsBinaryTree(TreeNode* root){
		if(root==NULL)return true;
		if(IsBinaryTree(root->left) && IsBinaryTree(root->right))
			return CompareLeft(root->left,root->val)&&CompareRight(root->right,root->val);
		return false;
	}

};

方法三

#include <iostream>
#include <vector>
using namespace std;

struct TreeNode{
	int val;
	TreeNode *left,*right;
	TreeNode(int x):val(x),left(NULL),right(NULL){}
	TreeNode():val(0),left(NULL),right(NULL){}
};

TreeNode trees[100003];

class Solution{
private:

	bool ret;
public:
	Solution(){
		ret=true;
	}
	pair<int,int> Traverse(TreeNode* root){
		pair<int,int> left,right;
		int val=root->val;
		if(root->left==NULL)
			left=make_pair(val,val-1);
		else
			left=Traverse(root->left);
		
		if(root->right==NULL)
			right=make_pair(val+1,val);
		else
			right=Traverse(root->right);

		if(left.second>=val||right.first<=val)
			ret=false;
		return make_pair(left.first,right.second);
	}
	bool IsBinaryTree(TreeNode* root){
		if(root==NULL)return true;
		Traverse(root);
		return ret;
		
	}
	void printPost(TreeNode* root){
		if(root==NULL)return;
		cout<<root->val<<" ";
		printPost(root->left);
		printPost(root->right);
	}
};
int main(){
	int n,rv;
	cin>>n>>rv;
	TreeNode *root=&trees[rv];
	int v,l,r;
	for(int i=1;i<=n;i++){
		cin>>v>>l>>r;
		trees[i].val=v;
		trees[i].left=l?&trees[l]:0;
		trees[i].right=r?&trees[r]:0;
	}
	Solution s;
	bool result=s.IsBinaryTree(root);
	if(result)
		cout<<"true"<<endl;
	else
		cout<<"false"<<endl;
}

当N=100000,方法二不能在1s内运行完成,无法AC。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值