617e. 合并二叉树
方法一:DFS递归
用时:6m25s
思路
- 时间复杂度: O ( m i n ( m , n ) ) O(min(m,n)) O(min(m,n))。
- 空间复杂度: O ( m i n ( m , n ) ) O(min(m,n)) O(min(m,n))。
C++代码
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if (root1 == nullptr) return root2;
if (root2 == nullptr) return root1;
root1->val += root2->val;
root1->left = mergeTrees(root1->left, root2->left);
root1->right = mergeTrees(root1->right, root2->right);
return root1;
}
};
方法二:BFS迭代
思路
首先要搞清楚要返回的对象,我们最终要返回root1,即我们要将合并得到的二叉树存储在原来以root1为根节点的二叉树(树1)中,因为为了节省空间,不新建二叉树,所以直接原地修改。
既然我们最终要将结果存放在树1中,那边迭代过程中节点修改的逻辑就要理清楚:
- 使用队列存放两棵树的节点,对应位置的节点存放在一起,且树1的节点在树2的节点前面,这意味着树1的节点比树2的节点先入队。并且队列中我们不存放空节点,原因见后面。
- 迭代的时候,每次弹出队头前两个节点,分别为node1和node2。由于我们树1最后是我们要返回的结果,所以我们要修改的是树1的节点,无需更改树2的节点。将node1的值更改为node1的值加node2的值。
- 接下来是处理当前两个节点的子节点。注意,如果node2不存在左(右)节点,那么node1的左(右)节点以及以左(右)节点为根节点的子树都不用进行任何修改。所以如果node2不存在左(右)节点的话,直接跳过,无需将node1的左(右)节点入队。
- 如果node2存在左(右)节点,当node1也存在左(右)节点时,将两者都入列。如果node1不存在左(右)节点时,直接让node1的左(右)节点赋值为node2的左(右)节点,且后续的子树也直接等于node2左(右)子树,不用进行其他处理,所以也不用入队。
本题的BFS解法与二叉树BFS遍历稍有不同,主要的不同点在于并不是每个节点都会入队,当我们确定了两棵树中某一棵树的子树为空时,后续的节点全都无需入队判断,直接赋值后跳过即可。
- 时间复杂度: O ( m i n ( m , n ) ) O(min(m,n)) O(min(m,n))。
- 空间复杂度: O ( m i n ( m , n ) ) O(min(m,n)) O(min(m,n))。
C++代码
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if (root1 == nullptr) return root2;
if (root2 == nullptr) return root1;
queue<TreeNode*> que;
que.push(root1);
que.push(root2);
while (!que.empty()) {
TreeNode* node1 = que.front();
que.pop();
TreeNode* node2 = que.front();
que.pop();
node1->val += node2->val;
if (node2->left) { // 只有node2左节点存在才需处理
if (node1->left) { // 如果node1也存在左节点
que.push(node1->left);
que.push(node2->left);
} else node1->left = node2->left; // 如果node1不存在左节点
}
if (node2->right) { // 只有node2右节点存在才需处理
if (node1->right) { // 如果node1也存在右节点
que.push(node1->right);
que.push(node2->right);
} else node1->right = node2->right; // 如果node1不存在右节点
}
}
return root1;
}
};
看完讲解的思考
本题的关键点在于其中一个节点为空直接返回另外一个节点,这一点做题的时候没有想到。
代码实现遇到的问题
无。
700e. 二叉搜索树中的搜索
方法一:DFS递归法
思路
目标值比当前节点小就继续搜索左子树,大就搜索右子树。
- 时间复杂度: O ( n ) O(n) O(n),最坏情况当树呈链状。
- 空间复杂度: O ( n ) O(n) O(n)。
C++代码
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if (root == nullptr) return nullptr;
if (root->val == val) return root;
return root->val < val ? searchBST(root->right, val) : searchBST(root->left, val);
}
};
方法二:迭代法
思路
由于每次判断只与当前节点有关,所以本题的迭代法无需使用栈,直接迭代更新当前节点即可。
- 时间复杂度: O ( n ) O(n) O(n)。
- 空间复杂度: O ( 1 ) O(1) O(1)。
C++代码
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
while (root) {
if (root->val == val) return root;
else if (root->val < val) root = root->right;
else root = root->left;
}
return nullptr;
}
};
看完讲解的思考
一开始思维固化了,想到DFS迭代法就建立了一个栈,但是本题用迭代法根本就不需要栈。
代码实现遇到的问题
无。
98m. 验证二叉搜索树
方法一:DFS递归法
用时:19m1s
思路
每次递归先判断当前节点的值是否位于上下界之间,否则返回false
;然后再递归判断左右节点,递归的时候更新上下界。注意本题陷阱,要使用long long
。
- 时间复杂度: O ( n ) O(n) O(n)。
- 空间复杂度: O ( n ) O(n) O(n)。
C++代码
class Solution {
private:
bool _isValidBST(TreeNode* node, long long minVal, long long maxVal) {
if (node->val <= minVal || node->val >= maxVal) return false;
bool leftFlag = true;
bool rightFlag = true;
if (node->left) leftFlag = _isValidBST(node->left, minVal, node->val);
if (node->right) rightFlag = _isValidBST(node->right, node->val, maxVal);
return leftFlag && rightFlag;
}
public:
bool isValidBST(TreeNode* root) {
return _isValidBST(root, LLONG_MIN, LLONG_MAX);
}
};
方法二:中序遍历递归法
思路
BST的性质:BST中序遍历的结果是有序数组。我们可以利用这一条性质来判断一棵树是不是BST。
在中序遍历过程中,用minVal记录当前的下界,递归过程中不断更新,且当前节点需要大于minVal。
- 时间复杂度: O ( n ) O(n) O(n)。
- 空间复杂度: O ( n ) O(n) O(n)。
C++代码
class Solution {
private:
long long minVal = LLONG_MIN;
public:
bool isValidBST(TreeNode* root) {
if (root == nullptr) return true;
bool leftFlag = isValidBST(root->left);
if (root->val <= minVal) return false;
minVal = root->val;
bool rightFlag = isValidBST(root->right);
return leftFlag && rightFlag;
}
};
方法三:中序遍历迭代法
思路
用一个指针记录中序遍历的前一个节点,然后比较当前节点是否大于前一个节点的值。
- 时间复杂度: O ( n ) O(n) O(n)。
- 空间复杂度: O ( n ) O(n) O(n)。
C++代码
class Solution {
public:
bool isValidBST(TreeNode* root) {
stack<TreeNode*> st;
TreeNode* cur = root;
TreeNode* pre = nullptr; // 用于记录中序遍历中前一个节点
while (cur || !st.empty()) {
if (cur) {
st.push(cur);
cur = cur->left;
} else {
cur = st.top();
st.pop();
if (pre && cur->val <= pre->val) return false; // 当前节点的值需要大于前一个节点
pre = cur;
cur = cur->right;
}
}
return true;
}
};
看完讲解的思考
代码实现遇到的问题
最后的碎碎念
今天刮台风“苏拉”,宅在宿舍。