1. 二叉树创建字符串。
给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。 要用括号分别括住左右子树 空节点使用一对空括号对 “()” 表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。 链接:力扣(LeetCode)
省略: 左右都为空 右子树为空,左子树不为空 若仅左为空,不省略 前序遍历
class Solution {
public:
string tree2str(TreeNode* root) {
if (root == nullptr)
return string();
string str;
str += to_string(root->val);
if (root->left || root->right)
{
str += '(';
str += tree2str(root->left);
str += ')';
}
if (root->right)
{
str += '(';
str += tree2str(root->right);
str += ')';
}
return str;
}
};
问题点:return str;是传值返回 解决:写一个子函数,用str的引用传参
?
2. 二叉树的分层遍历1。
链接
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
难点: 想办法去区分是否是同一层的结点 控制一层一层出——levelsize
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> q;
size_t levelSize = 0;
if (root)
{
q.push(root);
levelSize = 1;
}
vector<vector<int>> vv;
while (!q.empty())
{
vector<int> v;
for (size_t i = 0; i < levelSize; ++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);
levelSize = q.size();
}
return vv;
}
};
还有另外一种思路:双队列 1.存结点指针 2.存层数
?
3. 二叉树的分层遍历2。
链接
给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
逆置
reverse(vv.begin(),vv.end());
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
queue<TreeNode*> q;
size_t levelSize = 0;
if (root)
{
q.push(root);
levelSize = 1;
}
vector<vector<int>> vv;
while (!q.empty())
{
vector<int> v;
for (size_t i = 0; i < levelSize; ++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);
levelSize = q.size();
}
reverse(vv.begin(),vv.end());
return vv;
}
};
?
4. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” 链接:力扣(LeetCode)
规则:一个是左子树里的结点,一个是右子树的结点,那么他就是最近公共祖先
class Solution {
public:
bool Find(TreeNode* sub, TreeNode* x)
{
if (sub == nullptr)
{
return false;
}
return sub == x || Find(sub->left, x) || Find(sub->right, x);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == nullptr)
{
return nullptr;
}
if (root == p || root == q)
{
return root;
}
bool pInLeft, pInRight, qInLeft, qInRight;
pInLeft = Find(root->left, p);
pInRight != pInLeft;
qInLeft = Find(root->left, q);
qInRight != qInLeft;
if ((pInLeft && qInRight) || (qInLeft && pInRight))
{
return root;
}
else if (pInLeft && qInLeft)
{
return lowestCommonAncestor(root->left, p, q);
}
else if (pInRight && qInRight)
{
return lowestCommonAncestor(root->right, p, q);
}
else
{
return nullptr;
}
}
};
优化:O(H*N)——O(H)
class Solution {
public:
bool FindPath(TreeNode* root, TreeNode* x, stack<TreeNode*>& path)
{
if (root == nullptr)
return false;
path.push(root);
if (root == x)
return true;
if (FindPath(root->left, x, path))
return true;
if (FindPath(root->right, x, path))
return true;
path.pop();
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
stack<TreeNode*> pPath, qPath;
FindPath(root, p, pPath);
FindPath(root, q, qPath);
while (pPath.size() != qPath.size())
{
if (pPath.size() > qPath.size())
pPath.pop();
else
qPath.pop();
}
while (pPath.top() != qPath.top())
{
pPath.pop();
qPath.pop();
}
return pPath.top();
}
};
?
5. 二叉树搜索树转换成排序双向链表。
链接
注意: 1.要求不能创建任何新的结点,只能调整树中结点指针的指向。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继 2.返回链表中的第一个节点的指针 3.函数返回的TreeNode,有左右指针,其实可以看成一个双向链表的数据结构 4.你不用输出双向链表,程序会根据你的返回值自动打印输出
class Solution {
public:
void InOrderConvert(TreeNode* cur, TreeNode*& prev)
{
if (cur == nullptr)
{
return;
}
InOrderConvert(cur->left, prev);
cur->left = prev;
if (prev)
prev->right = cur;
prev = cur;
InOrderConvert(cur->right, prev);
}
TreeNode* Convert(TreeNode* pRootOfTree) {
TreeNode* prev = nullptr;
InOrderConvert(pRootOfTree, prev);
TreeNode*head = pRootOfTree;
while (head && head->left)
head = head->left;
return head;
}
};
?
6. 根据一棵树的前序遍历与中序遍历构造二叉树。
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。 链接:力扣(LeetCode) ![在这里插入图片描述](https://img-blog.csdnimg.cn/80dacb7baa124869961060990b7de541.png#pic_center
class Solution {
public:
TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder,int& prei,int inbegin, int inend) {
if (inbegin > inend)
return nullptr;
TreeNode* root = new TreeNode(preorder[prei++]);
int ini = inbegin;
while (ini <= inend)
{
if(inorder[ini] == root->val)
break;
else
++ini;
}
root->left = _buildTree(preorder, inorder, prei, inbegin, ini - 1);
root->right = _buildTree(preorder, inorder, prei, ini + 1, inend);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int i = 0;
return _buildTree(preorder,inorder,i,0,inorder.size()-1);
}
};
?
7. 根据一棵树的中序遍历与后序遍历构造二叉树。
链接
class Solution {
int post_idx;
unordered_map<int, int> idx_map;
public:
TreeNode* helper(int in_left, int in_right, vector<int>& inorder, vector<int>& postorder){
if (in_left > in_right) {
return nullptr;
}
int root_val = postorder[post_idx];
TreeNode* root = new TreeNode(root_val);
int index = idx_map[root_val];
post_idx--;
root->right = helper(index + 1, in_right, inorder, postorder);
root->left = helper(in_left, index - 1, inorder, postorder);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
post_idx = (int)postorder.size() - 1;
int idx = 0;
for (auto& val : inorder) {
idx_map[val] = idx++;
}
return helper(0, (int)inorder.size() - 1, inorder, postorder);
}
};
?
非递归的意义:
递归调用太深,容易奔溃。栈空间不大,会栈溢出 循环迭代,一般不会有空间的消耗 堆——动态申请 空间大
8. 二叉树的前序遍历,非递归迭代实现 。
链接
给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> v;
TreeNode* cur = root;
while (cur || !st.empty())
{
while (cur)
{
v.push_back(cur->val);
st.push(cur);
cur = cur->left;
}
TreeNode* top = st.top();
st.pop();
cur = top->right;
}
return v;
}
};
一个结点从栈里面出来意味着:这个结点及它的左子树访问完了,还剩右子树
?
9. 二叉树中序遍历 ,非递归迭代实现。
链接
给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> v;
TreeNode* cur = root;
while (cur || !st.empty())
{
while (cur)
{
st.push(cur);
cur = cur->left;
}
TreeNode* top = st.top();
st.pop();
v.push_back(top->val);
cur = top->right;
}
return v;
}
};
?
10. 二叉树的后序遍历 ,非递归迭代实现。
链接
给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。
一个结点右不为空的情况下: 1.右子树没有访问,访问右子树 2.右子树已经访问过了,访问根结点
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> v;
TreeNode* cur = root;
TreeNode* prev = nullptr;
while (cur || !st.empty())
{
while (cur)
{
st.push(cur);
cur = cur->left;
}
TreeNode* top = st.top();
if (top->right == nullptr || top->right == prev)
{
v.push_back(top->val);
prev = top;
cur = nullptr;
st.pop();
}
else{
cur = top->right;
}
}
return v;
}
};
|