IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 二叉树进阶oj题 -> 正文阅读

[数据结构与算法]二叉树进阶oj题

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中
                v.push_back(front->val);

               //下一层的进队列
                 if (front->left)
                {
                    q.push(front->left);
                }

                if (front->right)
                {
                    q.push(front->right);
                }
            }
            vv.push_back(v);//二维数组,一层一层
            
            //当前层出完了,下一层都进队列,队列的size就是下一层的数据个数
            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);
            //当前层出完了,下一层都进队列,队列的size就是下一层的数据个数
            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;

//1.一个在左一个在右,root就是最近公共祖先
//2.都在左,递归去左子树找
//3.都在右,递归去右子树找
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;
        }

        // 选择 post_idx 位置的元素作为当前子树根节点
        int root_val = postorder[post_idx];
        TreeNode* root = new TreeNode(root_val);

        // 根据 root 所在位置分成左右两棵子树
        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())
{
//开始访问一棵树——cur指向结点的树
//1.左路结点
while (cur)
{
v.push_back(cur->val);
st.push(cur);

cur = cur->left;
}

//2.左路结点的右子树需要访问
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())
{
//1.左路结点入栈
while (cur)
{

st.push(cur);

cur = cur->left;
}

//2.当左路结点从栈中出来,表示左子树已经访问过了,应该访问它的结点和他的右子树
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())
{
//1.左路结点入栈
while (cur)
{

st.push(cur);

cur = cur->left;
}

//2.当左路结点从栈中出来,表示左子树已经访问过了
TreeNode* top = st.top();

//栈顶结点右子树为空或上一个访问结点是右子树的根,说明右子树已经访问过了,可以访问这个栈顶结点
//否则 子问题访问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;
}
};
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-11-05 00:49:40  更:2022-11-05 00:52:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:25:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码