BM32 合并二叉树
递归做法:
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
class Solution {
public:
/**
*
* @param t1 TreeNode类
* @param t2 TreeNode类
* @return TreeNode类
*/
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
// write code here
return mergeOper(t1,t2);
}
TreeNode* mergeOper(TreeNode* t1,TreeNode* t2){
TreeNode* newTree;
TreeNode* other;
if((t1 == NULL)&&(t2 == NULL)){
return NULL;
}else{
if(t1 == NULL){
newTree = t2;
return newTree;
}else if(t2 == NULL){
newTree = t1;
return newTree;
}else{
newTree = t1;
newTree->val += t2->val;
}
other = (newTree == t1)?t2:t1;
newTree->left = mergeOper(newTree->left,other->left);
newTree->right = mergeOper(newTree->right,other->right);
return newTree;
}
}
};
思路解析:子问题,某两个对应位置结点t1,t2合并的四种情况:
(1)如果t1和t2均为空树,则合并后对应位置为空树NULL。
(2)如果t1为空树,t2不为空树,则合并后对应位置接t2。
(3)如果t2为空树,t1不为空树,则合并后对应位置接t1。
(4)如果t1,t2均不为空树,则合并后对应位置结点的值为t1->val + t2->val。
除此之外,为了尽可能少地分配空间,在原树上进行操作,减少空间复杂度。我们需判断这几种情况下t1和t2那棵树非空,非空的树用newTree来表示,另一棵树用other来表示:
(1)全为空,也就不用newTree和other了,直接return NULL。
(2)如果t1为空树,t2不为空树,newTree为t2,other为t1。
(3)如果t2为空树,t1不为空树,newTree为t1,other为t2。
(4)如果t1和t2均不为空树,则设newTree为t1,other为t2。
四种情况下,先分别找到newTree和other,按照上述分析合并,之后递归左右子树。
BM33 二叉树的镜像
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pRoot TreeNode类
* @return TreeNode类
*/
TreeNode* Mirror(TreeNode* pRoot) {
// write code here
if(pRoot != NULL){
ChangeMirror(pRoot);
}
return pRoot;
}
void ChangeMirror(TreeNode* root){
if(root->left == NULL && root->right == NULL){
return;
}else{
if(root->left != NULL && root->right!=NULL){
TreeNode* tmp = root->left;
root->left = root->right;
root->right = tmp;
ChangeMirror(root->left);
ChangeMirror(root->right);
}else if(root->left == NULL && root->right!=NULL){
root->left = root->right;
root->right = NULL;
ChangeMirror(root->left);
}else{
root->right = root->left;
root->left = NULL;
ChangeMirror(root->right);
}
}
}
};
思路:递归方式,从根节点开始,分四种情况讨论。
BM34 判断是不是二叉搜索树
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @return bool布尔型
*/
bool isValidBST(TreeNode* root) {
// write code here
bool flag = true;
TreeNode* cur = root;
TreeNode* pre = NULL;
stack<TreeNode*> s;
while(cur){
s.push(cur);
cur = cur->left;
}
while(!s.empty()||cur){
while(cur){
s.push(cur);
cur = cur->left;
}
cur = s.top();
if(pre!=NULL && cur->val <= pre->val){
flag = false;
break;
}else{
s.pop();
pre = cur;
cur = cur->right;
}
}
return flag;
}
};
思路:在二叉树的非递归中序遍历中改写visit(),在visit中判断pre->valval。
BM35 判断完全二叉树
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @return bool布尔型
*/
bool isCompleteTree(TreeNode* root) {
// write code here
if(root == NULL){
return false;
}else{
bool flag = true;
queue<TreeNode*> q;
TreeNode* tmp;
q.push(root);
int count = q.size();
int cmp_num = 1;
while(!q.empty()){
tmp = q.front();
if(tmp->left && tmp->right){
q.pop();
q.push(tmp->left);
q.push(tmp->right);
}else if(tmp->left == NULL && tmp->right!=NULL){
return false;
}else if(tmp->right == NULL && tmp->left!=NULL){
q.pop();
q.push(tmp->left);
break;
}else{
q.pop();
break;
}
}
while(!q.empty()){
tmp = q.front();
q.pop();
if(tmp->left!=NULL || tmp->right!=NULL){
return false;
}
}
return true;
}
}
};
思路:完全二叉树有个重要的性质,当存在某个结点没有左子树但有右子树时,该树肯定不是完全二叉树。
判断完全二叉树,肯定要用到层序遍历。结合重要的性质,就有了突破口。具体分四种情况讨论:
1.当前结点有左孩子和右孩子,则当前结点出队列,左右孩子分别入队列。
2.当前结点无左孩子但有右孩子,存在这样的结点,直接能够证明一定不是完全二叉树。
3.当前结点有左孩子无右孩子,则当前结点出队列,左孩子入栈,跳出while循环。
4.当前结点无左右孩子,当前结点出队列,跳出while循环。
出了while循环后,应该保证:当前还在队列中的结点均为叶子结点,否则不是完全二叉树。
BM36 判断平衡二叉树
除了递归,实在想不出什么好办法。求出左右子树的高度,判断高度差,如果高度差绝对值大于1,则不是平衡二叉树,否则继续递归判断。
class Solution {
public:
bool IsBalanced_Solution(TreeNode* pRoot) {
if(pRoot == NULL){
return true;
}else{
if(abs(GetDepth(pRoot->left)-GetDepth(pRoot->right))<=1){
return IsBalanced_Solution(pRoot->left)&&IsBalanced_Solution(pRoot->right);
}else{
return false;
}
}
}
int GetDepth(TreeNode* root){
if(root == NULL){
return 0;
}else{
return 1+max(GetDepth(root->left),GetDepth(root->right));
}
}
};
BM37 二叉搜索树的最近公共祖先
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @param p int整型
* @param q int整型
* @return int整型
*/
int lowestCommonAncestor(TreeNode* root, int p, int q) {
// write code here
while(true){
if((p<=root->val && q>=root->val)||
(p>=root->val && q<= root->val)){
break;
}else if(p<root->val && q<root->val){
root = root->left;
}else if(p>root->val && q>root->val){
root = root->right;
}
}
return root->val;
}
};
思路:从根节点开始,当根节点的值介于二叉树的某两个结点值中间时,就返回根节点的值;否则当当前根节点的值小于两个结点的值,就移向右子树,当当前根节点的值大于两个结点的值,就移向左子树。
BM 38 在二叉树中找公共祖先
所以节点值为5和节点值为1的节点的最近公共祖先节点的节点值为3,所以对应的输出为3。节点本身可以视为自己的祖先
本题为上一题的推广。
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
class Solution {
public:
/**
*
* @param root TreeNode类
* @param o1 int整型
* @param o2 int整型
* @return int整型
*/
int lowestCommonAncestor(TreeNode* root, int o1, int o2) {
// write code here
stack<bool> route1 = findRoute(root,o1);
stack<bool> route2 = findRoute(root,o2);
stack<bool> mroute1;
stack<bool> mroute2;
while(!route1.empty()){
mroute1.push(route1.top());
route1.pop();
}
while(!route2.empty()){
mroute2.push(route2.top());
route2.pop();
}
while(!mroute1.empty()&&!mroute2.empty()){
if(mroute1.top() == true && mroute2.top() == true){
root = root->left;
}else if(mroute1.top() == false && mroute2.top() == false){
root = root->right;
}else{
break;
}
mroute1.pop();
mroute2.pop();
}
return root->val;
}
stack<bool> findRoute(TreeNode* root,int val){
stack<bool> s1;
stack<TreeNode*> s2;
TreeNode* tmp = root;
while(tmp){
if(tmp->left){
s1.push(true);
}
s2.push(tmp);
tmp = tmp->left;
}
while(!s2.empty()||tmp){
while(tmp){
if(tmp->left){
s1.push(true);
}
s2.push(tmp);
tmp = tmp->left;
}
tmp = s2.top();
if(tmp->val == val){
break;
}else{
s2.pop();
if(tmp->right != NULL){
s1.push(false);
}else{
while(s1.top() == false){
s1.pop();
}
s1.pop();
}
tmp = tmp->right;
}
}
return s1;
}
};
思路:1)先找出5和1对应的从根节点开始的路径。用一个堆栈表示,如5为{左},1为{右},我们可以用true表示左,false表示右。相关操作可结合中序遍历二叉树完成。值得注意的思路是:当遍历到当前节点已无右子树且当前节点的值不为要找的值,则路径堆栈要将栈顶所有的false项和false项下的第一项true出栈,并转向上一个未遍历右孩子的父节点。
2)得到两个结点用堆栈表示的路径序列,就分别一个一个出栈,当发现一个节点的路径向左,另一个结点的路径向右时,就证明当前结点为最近公共祖先;当两个结点的当前路径均指向左,则指向当前结点的左孩子;当两个结点的当前路径均指向右,则指向当前结点的右孩子。
BM39 层序遍历序列化二叉树
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
char* Serialize(TreeNode *root) {
if(!root){
return NULL;
}
string ret;
queue<TreeNode*> q;
TreeNode* tmp = root;
q.push(tmp);
int count = q.size();
while(!q.empty()){
tmp = q.front();
if(tmp->val>=0){
ret += to_string(tmp->val);
ret += "&";
if(tmp->left){
q.push(tmp->left);
}else{
q.push(new TreeNode(-1));
}
if(tmp->right){
q.push(tmp->right);
}else{
q.push(new TreeNode(-1));
}
}else{
ret += "#&";
}
q.pop();
}
char* result = new char[ret.size()+1];
strcpy(result,ret.c_str());
return result;
}
TreeNode* Deserialize(char *str) {
if(!str){
return NULL;
}
string s(str);
int index = 0;
queue<TreeNode*> q;
TreeNode* tmp;
vector<string> v;
while(index<=s.length()-1){
if(str[index] == '#'){
v.push_back("#");
index += 2;
}else{
int count = index;
while(str[count]!='&'){
count++;
}
v.push_back(s.substr(index,count-index));
index = count+1;
}
}
int i = 0;
TreeNode* root = new TreeNode(stoi(v[i++],0,10));
q.push(root);
string m;
while(i<v.size()){
tmp = q.front();
q.pop();
m = v[i++];
if(m == "#"){
tmp->left = NULL;
}else{
TreeNode* addNew = new TreeNode(stoi(m,0,10));
q.push(addNew);
tmp->left = addNew;
}
m = v[i++];
if(m == "#"){
tmp->right = NULL;
}else{
TreeNode* addNew = new TreeNode(stoi(m,0,10));
q.push(addNew);
tmp->right = addNew;
}
}
return root;
}
};
思路:层序遍历的应用。
BM40 重建二叉树
根据中序和先序重建二叉树
递归方法,先序找根,中序分左右子树。
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if(pre.size() == 0){
return NULL;
}
TreeNode* root = new TreeNode(pre[0]);
int i=0;
for(;i<vin.size();i++){
if(vin[i] == pre[0]){
break;
}
}
vector<int> newPre1;
newPre1.clear();
newPre1.assign(pre.begin()+1,pre.begin()+1+i);
vector<int> newPre2;
newPre2.clear();
newPre2.assign(pre.begin()+1+i,pre.begin()+pre.size());
vector<int> newVin1;
newVin1.clear();
newVin1.assign(vin.begin(),vin.begin()+i);
vector<int> newVin2;
newVin2.clear();
newVin2.assign(vin.begin()+1+i,vin.begin()+vin.size());
root->left = reConstructBinaryTree(newPre1,newVin1);
root->right = reConstructBinaryTree(newPre2,newVin2);
return root;
}
};
BM41 输出二叉树的右视图
大意:先根据先序和中序重建二叉树,后输出右视图。所谓右视图,就是层序遍历每一层的最右一个结点。
vector<int> solve(vector<int>& xianxu, vector<int>& zhongxu) {
// write code here
TreeNode* root = buildTree(xianxu,zhongxu);
queue<TreeNode*> q;
q.push(root);
TreeNode* tmp;
int count = q.size();
vector<int> result;
while(!q.empty()){
while(count--){
tmp = q.front();
q.pop();
if(count == 0){
result.push_back(tmp->val);
}
if(tmp->left){
q.push(tmp->left);
}
if(tmp->right){
q.push(tmp->right);
}
}
count = q.size();
}
return result;
}
由于通过先序和中序构建二叉树的操作和BM40一模一样,所以封装成了函数buildTree,然后写一个层序遍历,在其中通过设定count变量,表示每层的结点数量,当节点数量还剩一个的时候,就添加到右视图中。