算法
(递归) $O(n)$
递归建立整棵二叉树:先递归创建左右子树,然后创建根节点,并让指针指向两棵子树。
具体步骤如下:
- 先利用前序遍历找根节点:前序遍历的第一个数,就是根节点的值;
- 在中序遍历中找到根节点的位置 $k$,则 $k$ 左边是左子树的中序遍历,右边是右子树的中序遍历;
- 假设左子树的中序遍历的长度是 $l$,则在前序遍历中,根节点后面的 $l$ 个数,是左子树的前序遍历,剩下的数是右子树的前序遍历;
- 有了左右子树的前序遍历和中序遍历,我们可以先递归创建出左右子树,然后再创建根节点;
时间复杂度分析
我们在初始化时,用哈希表(unordered_map<int,int>
)记录每个值在中序遍历中的位置,这样我们在递归到每个节点时,在中序遍历中查找根节点位置的操作,只需要 $O(1)$ 的时间。此时,创建每个节点需要的时间是 $O(1)$,所以总时间复杂度是 $O(n)$。
C++ 代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
unordered_map<int,int> pos;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n = preorder.size();
for (int i = 0; i < n; i ++ )
pos[inorder[i]] = i;
return dfs(preorder, inorder, 0, n - 1, 0, n - 1);
}
TreeNode* dfs(vector<int>&pre, vector<int>&in, int pl, int pr, int il, int ir)
{
if (pl > pr) return NULL;
int k = pos[pre[pl]] - il;
TreeNode* root = new TreeNode(pre[pl]);
root->left = dfs(pre, in, pl + 1, pl + k, il, il + k - 1);
root->right = dfs(pre, in, pl + k + 1, pr, il + k + 1, ir);
return root;
}
};
5555 以前的y总会写题解,现在y总不写了 555
没有用hash,没有看题解独立ac了,开心
多希望能把算法基础的题解写一下,不然太痛苦了
模板
想问下,如果中序遍历存在重复元素,用unordered_map来存放中序遍历元素对应的位置是不是有问题
题目中的限制一般都是有用的,题目中说明了不存在重复元素。
哈哈谢谢,没仔细看题目,大佬还没睡呢
正要休息呢
自荐题解: https://www.acwing.com/file_system/file/content/whole/index/content/5684403/
(包括变量说明 + 代码注意点)
为什么这个没有main函数?
我也想知道。。。
剑指offer 的题哇,都没有的吧
来一个只用一个函数的递归,利用有初始值的参数来实现
这代码写的真的优雅
这里有图解
https://leetcode.cn/leetbook/read/illustration-of-algorithm/99ljye/
auto left = bfs(preorder, pl+1, pl+k, inorder, il, k-1);
auto right = bfs(preorder, pl+k+1, pr, inorder, k+1, ir);
y总,为啥这样写过不去啊,-il 是干啥呢
同问
https://blog.csdn.net/qq_45638271/article/details/118906295?spm=1001.2014.3001.5501可以看一下这个博客
相对位置
pos[pre[pl]] - il;这句话啥意思
寻找前序的根节点在中序遍历中是在第几个位置
左子树长度
牛
为什么我把边界条件改成if (il > ir)就会出错呢?
我试了一下,改完之后也是正确的。你可能是其他地方写错了。
y总,请问下为什么这种做法在牛客上提交会超出内存限制, 在这里提交不会
我试了一下,上面的代码都可以过。
棒
中序遍历是不是也需要判断长度是不是为0
由于题目中说明了“数据保证合法”,所以只要前序遍历非空,那么中序遍历也一定非空。
几天前看面经 有 问存在重复元素本题该怎么解得情况- -没想出来 想请教y老师
结果不唯一,当所有数均相同时最多会有指数种答案。所以直接暴搜就行了,没有比这更快的算法了。
dfs函数里传入inorder没用吧
有用,因为
preorder
,inorder
是局部变量,每次dfs
都要使用。避免了每次去计算index的值
最坏情况下所有节点的左儿子都为空,那么就会递归 $n$ 层,每层会复制一遍数组,需要 $O(n)$ 的时间,那总共就需要 $O(n^2)$ 的时间了。
输入的前序遍历序列和中序遍历序列不匹配怎么办?
这道题目保证了前序遍历和中序遍历一定是匹配的。如果不匹配我们可以在递归函数开头判断两个序列的长度是否相同,如果不同,则说明不匹配,直接返回即可。
单纯的判断两个序列的长度并不能说明是否匹配吧
每次递归的时候都要判断长度是否相等,如果长度一直都相等,那就说明是匹配的