1.二叉树深度
int max(int a ,int b)
{
return a > b ? a : b;
}
int maxDepth(struct TreeNode* root)
{
if(root == NULL)
return 0;
int ret = max(maxDepth(root->left),maxDepth(root->right));
return ret + 1;
}
解题思想:二叉树深度 == max(左子树深度,右子树深度)+1;
2.翻转二叉树
class Solution {
public:
TreeNode* invertTree(TreeNode* root)
{
if(root == NULL)
return NULL;
TreeNode* tmp = root->left;
root->left = root->right;
root->right = tmp;
invertTree(root->left);
invertTree(root->right);
return root;
}
};
解题思路:不断交换左右子树,直到为空
3.相同的树
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q)
{
if(q == NULL && p == NULL)
return true;
if(q == NULL || p == NULL)
return false;
if(q->val != p->val)
return false;
return isSameTree(q->left,p->left) && isSameTree(q->right,p->right);
}
};
解题思路:问题拆分
两棵树不同的情况
1.结构不同
即p == NULL || q == NULL;
2.结点值不同
即p->val != q->val;
然后递归子树即可;
4.对称二叉树
class Solution {
public:
bool child(TreeNode* q,TreeNode* p)
{
if(q == nullptr && p == nullptr)
return true;
if(q == nullptr || p == nullptr)
return false;
if(q->val != p->val)
return false;
return child(q->right,p->left) && child(q->left,p->right);
}
bool isSymmetric(TreeNode* root)
{
if(root == nullptr)
return true;
return child(root->left,root->right);
}
};
解题思路:
化为子问题解决,最后递归求出左右子树是否对称;
5、二叉树的遍历
6.二叉树的层序遍历
先不考虑按层输出,写一个二叉树的层序遍历;
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root)
{
vector<vector<int>> vv;
queue<TreeNode*> q;
if(root)
q.push(root);
while(!q.empty())
{
TreeNode* front = q.front();
q.pop();
cout << front->val;
if(front->left)
q.push(front->left);
if(front->right)
q.push(front->right);
}
return vv;
}
};
在此基础上,加入分层输出模块即可
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root)
{
vector<vector<int>> vv;
queue<TreeNode*> q;
if(root)
q.push(root);
while(!q.empty())
{
int queue_size = q.size();
vector<int> v;
for(int i = 0; i < queue_size ;++i)
{
TreeNode* front = q.front();
q.pop();
v.push_back(front->val);
if(front->left)
q.push(front->left);
if(front->right)
q.push(front->right);
}
vv.push_back(v);
}
return vv;
}
};
解题思路:
可以用一个循环控制每层输出的节点数量,并插入数组,而循环的控制变量如何选取?
观察发现,队列的元素个数是不断增加的,上一次循环增加的节点数,恰好是第二次循环需要输出的元素个数,再将元素插入数组即可;
7.二叉树的层序遍历II
解题思路:在前一题的基础上加上逆置即可,使用库函数reverse;
8.二叉树的最近公共祖
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL)return NULL;
if(root == p||root == q)return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if(left && right)return root;
return left ? left : right; // 只有一个非空则返回该指针,两个都为空则返回空指针
}
};
解题思路:
1.如果俩个节点分别处于左右子树,则当前根节点就是最近公共祖先
2.如果当处于左子树,则返回递归到左子树的值,右子树亦然;
8.2搜索树的最近祖先
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL)return NULL;
if(p->val > root->val && q->val > root->val)
return lowestCommonAncestor(root->right, p, q);
else if(p->val < root->val && q->val < root->val)
return lowestCommonAncestor(root->left, p, q);
else return root;
}
};
解题思路:搜索树左子树都比自己小,右子树都比自己大;
利用该性质,可以分三类:
1.一个值比自己大,一个比自己小,则该节点就是最近祖先;
2.都比自己小,递归到左子树,比自己大,递归到右子树;
9.二叉树与双向链表
class Solution {
private:
Node* head;
Node* pre;
//cur中序遍历
void inorder(Node* cur) {
if (cur == nullptr)return;
inorder(cur->left);
//转换
//当pre不为空时 需要将cur->left = pre, pre->right = cur , 再将pre指向cur
if (pre != nullptr)
{
pre->right = cur;
cur->left = pre;
pre = cur;
}
else
{
//当pre为nullptr 时 表示cur->val 为最小即为head头结点 只需要令head = cur,再将pre指向cur
head = cur;
pre = cur;
}
inorder(cur->right);
}
public:
Node* treeToDoublyList(Node* root) {
if (root == nullptr)return root;
inorder(root);
//处理头尾
head->left = pre;
pre->right = head;
return head;
}
};
解题思路:
将搜索树转化为排序的双向链表
-
通过排序可以想到搜索树的特性,即中序为有序;
-
双向则为可以想到左右指向改为链表的前后指针;
综上:核心代码为
cur->left = pre;//
if(pre)
pre->right = cur;
pre = cur;
10.重建二叉树
class Solution {
public:
TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder ,int& prei ,int inbegin , int inend)
{
if(inbegin > inend)//传入空节点
return NULL;
TreeNode* root = new TreeNode(preorder[prei]);//根节点处于前序第一个位置
int rooti = inbegin;
//寻找中序根节点的位置
while(rooti < inend)
{
if(inorder[rooti] == preorder[prei])
break;
else
++rooti;
}
if(inbegin <= rooti-1)//递归重建左树
root->left = _buildTree(preorder,inorder,++prei,inbegin,rooti-1);
else
root->left = NULL;
if(inend >= rooti+1)//递归重建右树
root->right = _buildTree(preorder,inorder,++prei,rooti+1,inend);
else
root->right = NULL;
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
{
int prei = 0;
int inbegin = 0 , inend = inorder.size() - 1;
return _buildTree(preorder,inorder,prei,inbegin,inend);
}
};
解题思路:
- 二叉树的中序和前序可以重建一颗二叉树;
- 前序可以确定根节点的位置;
- 中序找到根节点后可以分为左右子树的递归重建;