文章目录
调整搜索二叉树两个错误的节点
题目
一颗二叉树原本是搜索二叉树,但其中两个节点调换了位置,使得这棵而出书不再是搜索二叉树,找到这两个错误节点并返回。已知所有节点值都不一样,给定二叉树头节点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;
}