二叉树问题之七

调整搜索二叉树两个错误的节点

题目

一颗二叉树原本是搜索二叉树,但其中两个节点调换了位置,使得这棵而出书不再是搜索二叉树,找到这两个错误节点并返回。已知所有节点值都不一样,给定二叉树头节点head,返回一个长度为2的二叉树节点类型数组err,err[0]表示第一个错误节点,err[1]表示另一个错误节点。

代码

如果中序遍历中出现两次降序,则第一个错误的节点为第一次降序时较大的节点,第二个错误的节点为第二次降序时较小的节点

vector<treeNode*> getTwoErrNode(treeNode* root)
{
	vector<treeNode*> res(2);
	if (root == NULL)
		return res;
	stack<treeNode*> s;
	treeNode* pre = NULL;
	while (!s.empty() || root != NULL)
	{
		if (root != NULL)
		{
			s.push(root);
			root = root->left;
		}
		else
		{
			root = s.top();
			s.pop();
			if (pre != NULL && pre->val > root->val)
			{
				res[0] = res[0] == NULL ? pre : res[0];
				res[1] = root;
			}
			pre = root;
			root = root->right;
		}
	}
	return res;
}

判断t1树是否包含t2树全部的拓扑结构

题目

给定彼此独立的两棵树头节点分别为t1和t2,判断t1树是否包含t2树全部的拓扑结构
进阶:判断t1树种是否有与t2树拓扑结构完全相同的子树,要求时间复杂度可以达到O(N+M)

代码

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

struct treeNode {
	int val;
	treeNode* left;
	treeNode* right;
	treeNode(int value) :val(value), left(NULL), right(NULL) {}
};

treeNode* createTree(int* input, int len)
{
	treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
	for (int i = 0; i < len; i++)
	{
		tree[i].val = input[i];
		tree[i].left = NULL;
		tree[i].right = NULL;
	}
	for (int i = 0; i <= len / 2 - 1; i++)
	{
		if (2 * i + 1 <= len - 1)
			tree[i].left = &tree[2 * i + 1];
		if (2 * i + 2 <= len - 1)
			tree[i].right = &tree[2 * i + 2];
	}
	return tree;
}
/*判断t1树是否包含t2树的全部拓扑结构*/
bool check(treeNode* h, treeNode* t2)
{
	if (t2 == NULL)
		return true;
	if (h == NULL || h->val != t2->val)
		return false;
	return check(h->left, t2->left) && check(h->right, t2->right);
}

bool contains(treeNode* t1, treeNode* t2)
{
	return check(t1, t2) || check(t1->left, t2) || check(t1->right, t2);
}

/*判断t1树中是否有与t2树拓扑结构完全相同的子树*/
/*若t1的节点数位N,t2的节点数为M,则最优解是时间复杂度为O(N+M)的方法*/
/*先将t1树进行序列化,之后将t2树进行序列化,使用KMP进行
两个字符串的匹配,如果t2是t1的子串,那么t1则包含t2的全部
拓扑结构,时间复杂度为O(M+N)*/
string serialByPreOrder(treeNode* root)
{
	if (root == NULL)
		return "#!";
	string res = to_string(root->val) + "!";
	res += serialByPreOrder(root->left);
	res += serialByPreOrder(root->right);
	return res;
}

int* getNextArray(char* ms, int len)
{
	if (len == 1)
		return new int[1] {-1};
	int* next = new int[len];
	next[0] = -1;
	next[1] = 0;
	int pos = 2;
	int cn = 0;
	while (pos < len)
	{
		if (ms[pos - 1] == ms[cn])
			next[pos++] = ++cn;
		else if (cn > 0)
			cn = next[cn];
		else
			next[pos++] = 0;
	}
	return next;
}

//KMP
int getIndexOf(string s, string m)
{
	if (s == "" || m == "" || m.size() < 1 || s.size() < m.size())
		return -1;
	int lens = s.size();
	int lenm = m.size();
	char* sc = (char*)malloc(sizeof(char) * lens);
	char* mc = (char*)malloc(sizeof(char) * lenm);
	memcpy(sc, s.c_str(), sizeof(char) * lens);
	memcpy(mc, m.c_str(), sizeof(char) * lenm);
	int mi = 0, si = 0;
	int* next = getNextArray(mc, lenm);
	while (si < lens && mi < lenm)
	{
		if (sc[si] == mc[mi])
		{
			si++;
			mi++;
		}
		else if (next[mi] == -1)
			si++;
		else
			mi = next[mi];
	}
	return mi == lenm ? si - mi : -1;
}

bool isSubTree(treeNode* t1, treeNode* t2)
{
	string t1Str = serialByPreOrder(t1);
	string t2Str = serialByPreOrder(t2);
	return getIndexOf(t1Str, t2Str) != -1;
}

int* getNext1(string s)
{
	if (s.size() < 1)
		return new int[1]{ -1 };
	int len = s.size();
	int* next = new int[len];
	next[0] = -1;
	int j = 0;
	int k = -1;
	while (j < len - 1)
	{
		if (k == -1 || s[j] == s[k])
		{
			if (s[++j] == s[++k])
				next[j] = next[k];
			else
				next[j] = k;
		}
		else
			k = next[k];
	}
	return next;
}

int main()
{
	int input1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	int input2[] = { 2, 4, 5, 8 };
	int len1 = 9;
	int len2 = 4;
	treeNode* tree1 = createTree(input1, len1);
	treeNode* tree2 = createTree(input2, len2);
	bool res1 = contains(tree1, tree2);
	if (res1)
		cout << "Tree2 is contained in Tree1!" << endl;
	else
		cout << "Not contained!" << endl;
	bool res2 = isSubTree(tree1, tree2);
	if (res2)
		cout << "Tree2 is subtree of tree1!" << endl;
	else
		cout << "Tree2 is not a subtree of tree1!" << endl;
	getchar();
	return 0;
}

先序、中序和后序数组两两结合重构二叉树

题目

一棵二叉树所有节点值均不同,给定这棵二叉树正确的先序、中序和后序数组。分别用三个函数实现任意两种数组结合重构原来的二叉树,返回重构二叉树的头节点。

代码

详细解释可参考原书籍

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;

struct treeNode {
	int val;
	treeNode* left;
	treeNode* right;
	treeNode(int data) :val(data), left(NULL), right(NULL) {}
};

treeNode* createTree(int input[], int len)
{
	treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
	for (int i = 0; i < len; i++)
	{
		tree[i].val = input[i];
		tree[i].left = NULL;
		tree[i].right = NULL;
	}
	for (int i = 0; i <= len / 2 - 1; i++)
	{
		if (2 * i + 1 < len)
			tree[i].left = &tree[2 * i + 1];
		if (2 * i + 2 < len)
			tree[i].right = &tree[2 * i + 2];
	}
	return tree;
}

void printTree(treeNode* root)
{
	if (root == NULL)
		return;
	cout << root->val;
	printTree(root->left);
	printTree(root->right);
}

treeNode* preInToTree(int pre[], int pi, int pj, int in[], int ni, int nj)
{
	if (pi > pj || ni > nj)
		return NULL;
	treeNode* root = new treeNode(pre[pi]);
	int i;
	for (i = 0; i < nj; i++)
	{
		if (in[i] == pre[pi])
			break;
	}
	root->left = preInToTree(pre, pi + 1, pi + i - ni, in, ni, i - 1);
	root->right = preInToTree(pre, pi + i - ni + 1, pj, in, i + 1, nj);
	return root;
}//同时可以使用map存储节点及其对应的位置,这样可以使得整个过程的时间复杂度达到O(N)

/*中序和后序重构的过程与先序和中序的过程类似,使用后序最右的值来划分中序数组即可*/
treeNode* inPosToTree(int in[], int ni, int nj, int pos[], int pi, int pj)
{
	if (ni > nj)
		return NULL;
	treeNode* root = new treeNode(pos[pj]);
	int i;
	for (i = 0; i < nj; i++)
	{
		if (in[i] == pos[pj])
			break;
	}
	root->left = inPosToTree(in, ni, i - 1, pos, pi, pi + i - ni - 1);
	root->right = inPosToTree(in, i + 1, nj, pos, pi + i - ni, pj - 1);
	return root;
}

/*先序和后序重构二叉树较为复杂,因为在许多结构不同的树种,先序与后序数组是相同的
如果在一颗二叉树中除了叶节点之外,其余所有节点都有左孩子和右孩子,那么这样的树可以
被先序和后序数组重构出来*/
treeNode* prePosToTree(int pre[], int pi, int pj, int pos[], int si, int sj)
{
	treeNode* root = new treeNode(pos[sj]);
	if (pi == pj)  //递归要确定返回根结点时的情况;
		return root;
	int i;
	for (i = 0; i < pj; i++)
	{
		if (pos[i] == pre[pi + 1])
			break;
	}
	root->left = prePosToTree(pre, pi + 1, pi + i - si + 1, pos, si, i);
	root->right = prePosToTree(pre, pi + i - si + 2, pj, pos, i + 1, sj - 1);
	return root;
}

/*通过先序和中序数组生成后序数组*/
int setPos(int pre[], int pi, int pj, int n[], int ni, int nj, int* &pos, int si, map<int, int> mp)
{
	if (pi > pj)
		return si;
	pos[si--] = pre[pi];
	int i = mp[pre[pi]];
	si = setPos(pre, pj - nj + i + 1, pj, n, i + 1, nj, pos, si, mp);
	return setPos(pre, pi + 1, pj - nj + i, n, ni, i - 1, pos, si, mp);
}

int* getPosArray(int pre[], int in[], int len)
{
	if (pre == NULL || in == NULL)
		return NULL;
	int* pos = new int[len];
	map<int, int> m;
	for (int i = 0; i < len; i++)
		m.insert(pair<int, int>(in[i], i));
	setPos(pre, 0, len - 1, in, 0, len - 1, pos, len - 1, m);
	return pos;
}

int main()
{
	int pre[] = { 1, 2, 4, 5, 3, 6, 7 };
	int preLen = 7;
	int in[] = { 4, 2, 5, 1, 6, 3, 7 };
	int inLen = 7;
	int pos[] = { 4, 5, 2, 6, 7, 3, 1 };
	int posLen = 7;
	treeNode* root = preInToTree(pre, 0, preLen - 1, in, 0, inLen - 1);
	printTree(root);
	cout << endl;
	treeNode* root1 = inPosToTree(in, 0, inLen - 1, pos, 0, posLen - 1);
	printTree(root1);
	cout << endl;
	treeNode* root2 = prePosToTree(pre, 0, preLen - 1, pos, 0, posLen - 1);
	printTree(root2);
	cout << endl;
	int* posG = (int*)malloc(sizeof(int) * preLen);
	posG = getPosArray(pre, in, preLen);
	for (int i = 0; i < preLen; i++)
	{
		cout << posG[i] << " ";
	}
	cout << endl;
	getchar();
	return 0;
}

在二叉树中找到一个节点的后继节点

题目

新的二叉树节点类型中包含一个指向父节点的parent指针。在二叉树中序遍历序列中,node的下一个节点叫做node的后继节点。详细题目可参考原书

代码

struct pnode {
	int value;
	pnode* left;
	pnode* right;
	pnode* parent;
	pnode(int data):value(data), left(NULL), right(NULL), parent(NULL){}
};

pnode* getLeftMost(pnode* root)
{
	if (root == NULL)
		return NULL;
	while (root->left != NULL)
		root = root->left;
	return root;
}

pnode* postNode(pnode* node)
{
	if (node == NULL)
		return NULL;
	if (right != NULL)
		return getLeftMost(node);
	else
	{
		pnode* parent = node->parent;
		while (parent != NULL && parent->left != node)
		{
			node = parent;
			parent = node->parent;
		}
		return parent;
	}
}
/*1、当节点存在右子树时,后继结点为右子树的最左节点
2、若当前节点不存在右子树,则向上查找父节点,直到当前节点
是父节点的左子树,返回父节点*/

在二叉树中找到两个节点的最近公共祖先

题目

给定一棵二叉树的头节点head,以及这棵树中两个节点o1和o2,请返回o1和o2的最近公共祖先节点。

代码

#include<iostream>
#include<map>
#include<set>
#include<string>
using namespace std;

struct treeNode {
	int val;
	treeNode* left;
	treeNode* right;
	treeNode(int data)
	{
		val = data;
		left = NULL;
		right = NULL;
	}
};

treeNode* createTree(int* input, int len)
{
	treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
	for (int i = 0; i < len; i++)
	{
		tree[i].val = input[i];
		tree[i].left = NULL;
		tree[i].right = NULL;
	}
	for (int i = 0; i <= len / 2 - 1; i++)
	{
		if (2 * i + 1 <= len - 1)
			tree[i].left = &tree[2 * i + 1];
		if (2 * i + 2 <= len - 1)
			tree[i].right = &tree[2 * i + 2];
	}
	return tree;
}

//后序遍历的过程寻找节点的公共节点
treeNode* lowestAncestor(treeNode* root, treeNode* o1, treeNode* o2)
{
	if (root == NULL || root == o1 || root == o2)
		return root;
	treeNode* left = lowestAncestor(root->left, o1, o2);
	treeNode* right = lowestAncestor(root->right, o1, o2);
	if (left != NULL && right != NULL)
		return root;
	return left != NULL ? left : right;
}

void setMap(treeNode* root, map<treeNode*, treeNode*> &m)
{
	if (root == NULL)
		return;
	if (root->left != NULL)
		m.insert(pair<treeNode*, treeNode*>(root->left, root));
	if (root->right != NULL)
		m.insert(pair<treeNode*, treeNode*>(root->right, root));
	setMap(root->left, m);
	setMap(root->right, m);
}

void record1(treeNode* root, map<treeNode*, treeNode*> &m)
{
	treeNode* nu = new treeNode(INT_MAX);
	if (root != NULL)
		m.insert(pair<treeNode*, treeNode*>(root, nu));
	setMap(root, m);
}

treeNode* query(treeNode* o1, treeNode* o2, map<treeNode*, treeNode*> &m)
{
	set<treeNode*>path;
	while (m.find(o1) != m.end())
	{
		path.insert(o1);
		o1 = m[o1];
	}
	while (path.find(o2) == path.end())
		o2 = m[o2];
	return o2;
}

int main()
{
	int input[] = { 1, 2, 3, 4, 5, 6, 7 };
	int len = 7;
	treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
	tree = createTree(input, len);
	treeNode* o1 = &tree[4];
	treeNode* o2 = &tree[2];
	treeNode* lowestAn1 = lowestAncestor(tree, o1, o2);
	cout << to_string(o1->val) + " and " + to_string(o2->val) + " ancestor " << lowestAn1->val << endl;
	treeNode* o3 = &tree[5];
	treeNode* o4 = &tree[6];
	map<treeNode*, treeNode*> m;
	setMap(tree, m);
	treeNode* lowestAn2 = query(o3, o4, m);
	cout << "The ancestor is " << lowestAn2->val << endl;
	getchar();
	return 0;
}

二叉树节点间的最大距离问题

题目

从二叉树的节点A出发,可以向上或向下走,但沿途的节点只能经过一次,当达到节点B时,路径上的节点数叫做A到B的距离。
如果二叉树的节点数为N,时间复杂度要求为O(N)

代码

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

struct treeNode {
	int val;
	treeNode* left;
	treeNode* right;
	treeNode(int data):val(data), left(NULL), right(NULL){}
};

treeNode* createTree(int input[], int len)
{
	treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
	for (int i = 0; i < len; i++)
	{
		tree[i].val = input[i];
		tree[i].left = NULL;
		tree[i].right = NULL;
	}
	for (int i = 0; i <= len / 2 - 1; i++)
	{
		if (2 * i + 1 < len)
			tree[i].left = &tree[2 * i + 1];
		if (2 * i + 2 < len)
			tree[i].right = &tree[2 * i + 2];
	}
	return tree;
}

int postOrder(treeNode* root, int record[])
{
	if (root == NULL)
	{
		record[0] = 0;
		return 0;
	}
	int lMax = postOrder(root->left, record);
	int maxFromLeft = record[0];
	int rMax = postOrder(root->right, record);
	int maxFromRight = record[0];
	int curNodeMax = maxFromLeft + maxFromRight + 1;
	record[0] = max(maxFromLeft, maxFromRight) + 1;
	return max(max(lMax, rMax), curNodeMax);
}

int maxDis(treeNode* root)
{
	int *record = new int[1];
	int maxD = postOrder(root, record);
	delete[] record;
	return maxD;
}

int main()
{
	int input[] = { 1, 2, 3, 4, 5, 6, 7 };
	int len = 7;
	treeNode* root = createTree(input, len);
	int maxD = maxDis(root);
	cout << maxD << endl;
	getchar();
	return 0;
}
/*假设子树头节点为h,处理h的左子树,左子树上最大距离为lMax,左子树上距离h
的左孩子的最远距离为maxFromLeft;处理h右子树得到右子树上的最大距离为rMax和距离h
右孩子的最远距离记为maxFromRight,那么maxFromLeft+1+maxFromRIght就是跨h节点情况下
的最大距离,再与lMax和rMax比较,把三者中的最值作为h树上的最大距离返回*/

统计完全二叉树的节点数

题目

给定一棵完全二叉树的头节点head,返回这棵树的节点个数。
要求如果完全二叉树的节点数为N,实现时间复杂度低于O(N)的解法。

代码

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

struct treeNode {
	int val;
	treeNode* left;
	treeNode* right;
	treeNode(int data) : val(data), left(NULL), right(NULL){}
};

treeNode* createTree(int input[], int len)
{
	treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
	for (int i = 0; i < len; i++)
	{
		tree[i].val = input[i];
		tree[i].left = NULL;
		tree[i].right = NULL;
	}
	for (int i = 0; i <= len / 2 - 1; i++)
	{
		if (2 * i + 1 < len)
			tree[i].left = &tree[2 * i + 1];
		if (2 * i + 2 < len)
			tree[i].right = &tree[2 * i + 2];
	}
	return tree;
}
/*如果树有h层, 找到根节点右子树的最左节点,两种情况:
最左节点能达到h层;最左节点无法到达h层*/
int mostLeftLevel(treeNode* root, int level)
{
	while (root != NULL)
	{
		level++;
		root = root->left;
	}
	return level - 1;
}

int bs(treeNode* root, int l, int h)
{
	if (l == h)
		return 1;
	if (mostLeftLevel(root->right, l + 1) == h)
		return (1 << (h - 1)) + bs(root->right, l + 1, h);
	else
		return (1 << (h - l - 1)) + bs(root->left, l + 1, h);
}

int nodeNum(treeNode* root)
{
	if (root == NULL)
		return 0;
	return bs(root, 1, mostLeftLevel(root, 1));
}

int main()
{
	int input[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
	int len = 8;
	treeNode* root = createTree(input, len);
	int nodeN = nodeNum(root);
	cout << "Total number of node: " << nodeN << endl;
	getchar();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值