最大二叉树
思路上这道题与昨天的从遍历数组构造二叉树那道题是一致的,也是进行一层一层的递归。有几点需要注意:这种题最好不要在递归函数中进行数组的切分,而是尽量用下标作为递归参数,可以减小时间和空间。另外,递归终止条件是叶子节点还是空指针,与递归时是否需要验证数组长度为0是相互对应的。
class Solution{
public:
TreeNode* traversal(vector<int>& nums, int left, int right){
if(left == right) return NULL;
int maxIndex = left;
for(int i = left + 1; i < right; i++){
if(nums[i] > nums[maxIndex]){
maxIndex = i;
}
}
TreeNode* root = new TreeNode(nums[maxIndex]);
root->left = traversal(nums, left, maxIndex);
root->right = traversal(nums, maxIndex + 1, right);
return root;
}
TreeNode* constructMaximumBinaryTree(vector<int>& nums){
return traversal(nums, 0, nums.size());
}
};
合并二叉树
与对称二叉树那道题比较相似,这道题也是处理两个二叉树,我们仍然是先实现递归法。
class Solution{
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2){
if(!root2) return root1; // 如果root2为空,那么返回root1作为节点,这样就不需要继续处理root1的子树了
if(!root1) return root2;
// 两个树的当前节点都不为空
TreeNode* root = new TreeNode(0);
root->val = root1->val + root2->val;
root->left = mergeTrees(root1->left, root2->left);
root->right = mergeTrees(root1->right, root2->right);
return root;
}
};
对于中间节点的加和处理,前中后序都是可以的。
迭代法中,一般一起操作两个树都是使用队列模拟层序遍历,同时处理两个树的节点。
class Solution{
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2){
if(!root2) return root1;
if(!root1) return root2;
// 两个树都不空
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(node1->left != NULL && node2->left != NULL){
que.push(node1->left);
que.push(node2->left);
}
if(node1->right != NULL && node2->right != NULL){
que.push(node1->right);
que.push(node2->right);
}
// 如果第一棵树的子节点为空,就把第二棵树的节点接上来
if(node1->left == NULL && node2->left != NULL){
node1->left = node2->left;
}
if(node1->right == NULL && node2->right != NULL){
node1->right = node2->right;
}
// 如果第二棵树的子节点是空的,则不需要进一步处理第一棵树子节点了,不用入队列
}
return root1;
}
};
二叉搜索树中的搜索
由于二叉搜索树的性质,我们可以使用一些更简单的方法遍历节点。
class Solution{
public:
TreeNode* searchBST(TreeNode* root, int val){
// 返回条件,如果遇到了空节点或者找到了相等值,将节点返回
if(root == NULL || root->val == val) return root;
TreeNode* result; // 按值来判断向左还是向右遍历
if(val > root->val) result = searchBST(root->right, val);
if(val < root->val) result = searchBST(root->left, val);
return result;
}
};
迭代法也比之前的栈模拟或队列模拟更简单。由于二叉搜索树的有序性,遍历是不需要回溯的,方向是确定的。
class Solution{
public:
TreeNode* searchBST(TreeNode* root, int val){
while(root != NULL){
if(val < root->val) root = root->left;
else if(val > root->val) root = root->right;
else return root;
}
return root;
}
};
验证二叉搜索树
二叉搜索树的中序遍历序列是一个单调递增序列。
class Solution{
public:
void traversal(TreeNode* node, vector<int>& vec){
if(node == NULL) return;
traversal(node->left, vec);
vec.push_back(node->val);
traversal(node->right, vec);
}
bool isValidBST(TreeNode* root){
if(!root) return true;
vector<int> vec;
traversal(root, vec);
for(int i = 1; i < vec.size(); i++){
if(vec[i] <= vec[i - 1]) return false;
}
return true;
}
};
我们也可以在中序遍历过程同时进行比较递归的方法。必须注意两点:
- 不能单单判断左右子节点和父节点之间的关系。而是判断左右子树与父节点之间的关系。
- 注意给出的测试示例,存在元素值比
INT_MIN
要小的情况,所以需要定义最小值为long long maxVal = LONG_MIN
。
这道题也是不需要遍历整个树,遇到不满足的情况及时返回就行,所以递归函数需要返回值来判断。
class Solution{
public:
long long maxVal = LONG_MIN;
bool isValidBST(TreeNode* root){
if(root == NULL) return true; // 二叉搜索树可以为空
// 中序遍历
if(!isValidBST(root->left)) return false;
if(maxVal < root->val) maxVal = root->val; // 处理中间节点,与中序上一个节点的值比较,确保单调递增
else return false;
if(!isValidBST(root->right)) return false;
return true;
}
};
也可以迭代法来实现中序遍历。这里注意变量的定义域,不要在循环内部新建同名节点,循环时判断时不会更新的。
class Solution{
public:
bool isValidBST(TreeNode* root){
if(root == NULL) return true;
stack<TreeNode*> st;
TreeNode* cur = root;
TreeNode* pre = NULL;
while(cur != NULL || !st.empty()){
if(cur != NULL){
cur = cur->left;
st.push(cur);
}
else{
cur = st.top();
st.pop();
if(pre != NULL && pre->val >= cur->val) return false;
pre = cur;
cur = cur->right;
}
}
return true;
}
};