重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
题目分析
先序遍历的首个元素就是树的根节点。我们在先序遍历中找到根节点,然后就可以根据根节点在中序遍历的数组中(因为题目说了树中没有重复的元素),将其划分为左子树 | 根节点 | 右子树。这样再分别递归其左右子树,即可重建整个二叉树。难点就在于递归需要传入的参数。这里先给出答案,需要的3个参数是1.根节点在前序遍历的索引,2.子树在中序遍历的左边界,3.子树在中序遍历的右边界。这是因为需要左右边界来确定退出条件,需要根节点来在中序遍历中划分界限。左子树的根节点直接就是原来的根节点root+1就好了,右子树的根节点需要先确定左子树的长度,而这个长度在中序遍历里可以知道,就是根节点在中序遍历的位置的左边。
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
// 输入的应该是先序遍历中根节点的位置。还有左子树的起点,右子树的终点。
// 容易知道的是,先序遍历先是 根节点|左子树|右子树。
// 这样就可以知道,当遍历左子树时候,这一左子树自己的根节点应该是root+1,
// 右子树的根节点则在左子树结束后的下一个节点。
// 先序遍历一开始的节点就是根节点。
// 找到中序遍历的根节点的位置,从这个位置往前的都是根节点
// 中序遍历找根节点的位置可以利用hash。
// 的左子树,往后的都是根节点的右子树。这样在分别递归这两颗子树。
this->preorder = preorder;
for (int i = 0; i < inorder.size(); i++){
map[inorder[i]] = i;
}
return recur(0, 0, inorder.size()-1);
}
TreeNode* recur(int root, int left, int right){
//退出条件。
if (left > right) return nullptr;
//递归
TreeNode* node = new TreeNode(preorder[root]);
int i = map[preorder[root]];
//返回值。
node->left = recur(root+1, left, i-1);
node->right = recur(root-left+i+1, i+1, right);
return node;
}
private:
vector<int> preorder;
unordered_map<int, int> map;
};
数值的整数次方
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。
没啥好说的,看解析吧。
leetcode: https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/57p2pv/.
二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
题目分析
首先这是一颗二叉搜索树。二叉搜索树的左子树的值都小于根节点,右子树的值都大于根节点。其次是后序遍历,其区域划分为左子树 | 右子树 | 根节点。关键来了,最后一个树即是根节点,当我们遍历数组,发现第一个大于根节点的数字,那么此数字就可以划分区域,将问题分而治之。左右子树的最后一个数字便是它们各自的根节点。这样我们可以递归左右子树。递归参数这次挺容易想到的,应该是一棵树的左右边界,加上这个数组。退出条件便是左边界大于或者等于右边界。递归想到了,二叉搜索树的判断条件还没有呢,应该就是上面所说的二叉搜索树的特性,通过两个循环来进行左右子树与根节点的大小比较,而我们划分的时候已经保证过左子树的正确性,所以现在我们只需要判断右子树区间就可以了。自己写的应该跟大佬的差不多,但是估计是测试样例太少了,稍微一点差距就造成只beat了29%。
法1
class Solution {
public:
bool verifyPostorder(vector<int>& postorder) {
return dfs(postorder, 0, postorder.size()-1);
}
bool dfs(vector<int>& postorder, int i, int j){
// 根节点总在最后一个,寻找第一个大于根节点的数字,以此为界划分区域假设此数字Index为m。
// 那么0到m-1为左子树,m到j-1为右子树。
// 左子树的最后一个又为它的根节点,在据此划分,右子树同理。
// 退出条件 是什么呢?左子树中的树都应该小于根节点,右子树的数都应该大于根节点。
if (i>=j) return true;
int m;
for (int k = 0; k < j; k++){
if (postorder[k] > postorder[j]){
m = k;
break;
}
}
// for(int l = i; l < m;l++){
// if (postorder[l] > postorder[j]) return false;
// }
for(int l = m; l < j; l++){
if (postorder[l] < postorder[j]) return false;
}
return dfs(postorder, i, m-1) && dfs(postorder, m+1, j-1);
}
};
法2
有点难懂,看链接吧
链接: https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/5vwbf6/.