leecode 解题总结:95. Unique Binary Search Trees II

#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
/*
问题:
Given an integer n, generate all structurally unique BST's (binary search trees) that store values 1...n.

For example,
Given n = 3, your program should return all 5 unique BST's shown below.

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

分析:这道题目实际上就是构建二叉查找树。二叉查找树由于不能调整位置,因此输入的
数据顺序会对树的形状产生影响。可以每次尝试不同的输入顺序:
比如1,2,3或者1,3,2;或者2,1,3;或者3,1,2或者3,2,1
但是即使用不同的顺序,可能会产生重复,比如:2,1,3和2,3,1产生的树的形状是一样的。
根本原因在于选用的根节点恰好是中间的数据。
简单的方式就是:每次产生一棵树,就和之前产生的所有树比较,看是否重复,如果重复
就过滤。
判断两棵树是否相同,可以递归得判定。
先判定两棵树当前结点值是否相同,如果不相同,直接返回两棵树不同;
否则,递归判定当前结点的左右子树是否相同即可

对于不同的输入:这个需要通过排列生成

输入:
3
输出:
1 3 2,3 2 1,3 1 2,2 1 3,1 2 3

关键:
1 采用排列+构建二叉查找树+去重做
2 leecode解法:https://leetcode.com/problems/unique-binary-search-trees-ii/?tab=Solutions
 由于二叉查找树是中序,因此,可以选定[1...n]中任意数i为根节点,
 那么左子树为[1...i-1],右子树为[i+1...len]
 如果发现左边=右边,说明当前要生成的就是一个结点,就把结点当做根节点压入【参见n为1的情况】
 如果左边>右边,不可能,返回空插入

 本质是不断从给定的序列中选定一个成为根节点,令左半段成为左子树,令右半段成为右子树。
 牛逼,以后看到树的问题多从递归入手

 	//注意每颗子树中也会产生不同的根节点,因此返回的左子树也是一个数组,右子树也是一个数组,然后做笛卡尔积
	vector<TreeNode*> buildTree(int start , int end )
*/

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

class Solution {
public:
	//注意每颗子树中也会产生不同的根节点,因此返回的左子树也是一个数组,右子树也是一个数组,然后做笛卡尔积
	vector<TreeNode*> buildTree(int start , int end )
	//TreeNode* buildTree(int start , int end,  vector<TreeNode*>& result)
	{
		vector<TreeNode*> result;
		 //递归出口,返回的NULL,实际上可能是
		if(start > end)
		{
			result.push_back(NULL);
			return result;
		}
		//只提供一个结点,则直接是根节点,后续会遍历到这里
		if(start == end)
		{
			TreeNode* node = new TreeNode(start);
			result.push_back(node);
			return result;
		}
		vector<TreeNode*> lefts;
		vector<TreeNode*> rights;
		int leftSize;
		int rightSize;
		for(int i = start ; i <= end ; i++)
		{
			lefts = buildTree(start  , i - 1);
			rights = buildTree(i + 1 , end);
			leftSize = lefts.size();
			rightSize = rights.size();
			for(int j = 0 ; j < leftSize; j++)
			{
				for(int k = 0 ; k < rightSize ; k++)
				{
					TreeNode* root = new TreeNode(i);
					root->left = lefts.at(j);
					root->right = rights.at(k);
					result.push_back(root);
				}
			}
		}
		return result;
	}

    vector<TreeNode*> generateTrees(int n) {
		vector<TreeNode*> nodes;
		if(n <= 0)
		{
			return nodes;
		}
		nodes = buildTree(1 , n);
		return nodes;
	}
};

class Solution2 {
public:
	void permutate(int n,int pos , vector<int>& result, vector< vector<int> >& results)
	{
		if(pos == n)
		{
			results.push_back(result);
			return;
		}
		bool isOk;
		for(int i = 1 ; i <= n ; i++)
		{
			isOk = true;
			for(int j = 0 ; j < pos ; j++)
			{
				if(i == result.at(j))
				{
					isOk = false;
					break;
				}
			}
			if(isOk)
			{
				result.push_back(i);
				permutate(n , pos + 1 , result , results);
				result.pop_back();
			}
		}
	}

	TreeNode* insertNode(TreeNode* root , int value)
	{
		if(!root)
		{
			return NULL;
		}
		//如果给定值> 根节点值,如果右孩子为空,作为右孩子,否则以右孩子作为根节点,递归
		if(value >= root->val)
		{
			if(NULL == root->right)
			{
				TreeNode* node = new TreeNode(value);
				root->right = node;
			}
			else
			{
				insertNode(root->right , value);	
			}
		}
		else
		{
			if(NULL == root->left)
			{
				TreeNode* node = new TreeNode(value);
				root->left = node;
			}
			else
			{
				insertNode(root->left , value);
			}
		}
		return root;
	}

	bool isSameTree(TreeNode* root1 , TreeNode* root2)
	{
		//如果两个当前结点都为空,则相同
		if(NULL == root1 && NULL ==  root2)
		{
			return true;
		}
		else if(NULL == root1)
		{
			return false;
		}
		else if(NULL == root2)
		{
			return false;
		}
		if(root1->val != root2->val)
		{
			return false;
		}
		return isSameTree(root1->left , root2->left) && isSameTree(root1->right ,root2->right);
	}

	//判断当前二叉查找树是否和集合中的二叉查找树重复
	bool isRepeated(vector<TreeNode*>& nodes , TreeNode* root)
	{
		if(nodes.empty())
		{
			return false;
		}
		int size = nodes.size();
		for(int i = 0 ; i < size ; i++)
		{
			if(isSameTree(nodes.at(i) , root))
			{
				return true;
			}
		}
		return false;
	}

    vector<TreeNode*> generateTrees2(int n) {
		vector<TreeNode*> nodes;
		if(n <= 0)
		{
			return nodes;
		}
        vector< vector<int> > results;
		vector<int> result;
		permutate(n , 0 , result , results);
		int size = results.size();
		//尝试不同的数据输入,来构建二叉树
		int len;
		for(int i = 0 ; i < size ; i++)
		{
			len = results.at(i).size();
			TreeNode* root = NULL;
			for(int j = 0 ; j < len ; j++ )
			{
				if(j)
				{
					root = insertNode(root , results.at(i).at(j)  );
				}
				//输入根节点
				else
				{
					root = new TreeNode( results.at(i).at(j) );
				}
			}

			//构建完了二叉查找树,下面判断是否重复
			if(nodes.empty())
			{
				nodes.push_back(root);
			}
			//如果
			else
			{
				//如果不重复
				if(!isRepeated(nodes , root))
				{
					nodes.push_back(root);
				}
			}
			
		}
		return nodes;
    }
};

//根左右
void preOrderVisit(TreeNode* root , vector<int>& result)
{
	if(NULL == root)
	{
		return;
	}
	if(root)
	{
		result.push_back(root->val);
	}
	preOrderVisit(root->left, result);
	preOrderVisit(root->right , result);
}

//打印每颗二叉查找树,用前序方式
void print(vector<TreeNode*>& result)
{
	if(result.empty())
	{
		cout << "no result" << endl;
		return;
	}
	int size = result.size();
	int len;
	for(int i = 0 ; i < size ; i++)
	{
		vector<int> datas;
		preOrderVisit(result.at(i) , datas);
		len = datas.size();
		for(int j = 0 ; j < len ; j++)
		{
			cout << datas.at(j) << " ";
		}
		cout << ",";
	}
	cout << endl;
}

//如果删除一棵树,只能先递归删除其左右子树,如果遇到一个结点没有左右孩子,就删除
void deleteTree(TreeNode* node)
{
	//如果当前结点为空,无需删除,直接返回
	if(!node)
	{
		return;
	}
	else if(NULL == node->left && NULL == node->right)
	{
		delete node;
		node = NULL;
	}
	if(node)
	{
		deleteTree(node->left);
		deleteTree(node->right);
	}
}

void deleteTrees(vector<TreeNode*>& nodes)
{
	if(nodes.empty())
	{
		return;
	}
	int size = nodes.size();
	for(int i = 0 ; i < size ; i++)
	{
		deleteTree(nodes.at(i));
	}
}

void process()
{
	 vector<int> nums;
	 int value;
	 int num;
	 Solution solution;
	 vector<TreeNode*> result;
	 while(cin >> num )
	 {
		 result = solution.generateTrees(num);
		 print(result);
		 deleteTrees(result);
	 }
}

int main(int argc , char* argv[])
{
	process();
	getchar();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值