今天是二叉树的第五天。主要学习的内容有:构建二叉树,合并二叉树,以及二叉搜索树的特性学习。
654.最大二叉树
题目链接:654. 最大二叉树 - 力扣(LeetCode)
这道题的要求是给一个数组,通过数组构建一个最大二叉树。即根节点为树的最大值。这个题感觉跟昨天的前中序构建二叉树思路是一致的。首先建立根节点,然后对数组分割为左子树和右子树,递归处理左子树和右子树。具体代码实现如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
if(nums.size()==0) return NULL;
int max_num=-10010;
int index=0;
for(int i=0;i<nums.size();i++)
{
if(nums[i]>max_num)
{
max_num=nums[i];
index=i;
}
}
TreeNode* root=new TreeNode(max_num);
if(nums.size()==1) return root;
vector<int> leftnums(nums.begin(),nums.begin()+index);
vector<int> rightnums(nums.begin()+index+1,nums.end());
root->left=constructMaximumBinaryTree(leftnums);
root->right=constructMaximumBinaryTree(rightnums);
return root;
}
};
617.合并二叉树
题目链接:617. 合并二叉树 - 力扣(LeetCode)
这个题考察的是对两棵树同时操作。和之前的对称二叉树思路是一致的。在没有看题解的情况下自己的实现代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
TreeNode* node=new TreeNode();
if(root1==NULL&&root2==NULL) return NULL;
else if(root1!=NULL&&root2==NULL)
{
int value=root1->val;
node->val=value;
node->left=mergeTrees(root1->left,NULL);
node->right=mergeTrees(root1->right,NULL);
}
else if(root1==NULL&&root2!=NULL)
{
int value=root2->val;
node->val=value;
node->left=mergeTrees(NULL,root2->left);
node->right=mergeTrees(NULL,root2->right);
}
else
{
int value1=root1->val;
int value2=root2->val;
int value=value1+value2;
node->val=value;
node->left=mergeTrees(root1->left,root2->left);
node->right=mergeTrees(root1->right,root2->right);
}
return node;
}
};
题解的代码更加的精简。对于有节点为空的情况,直接就返回存在的另一个子树。比我的对于单节点为空的情况处理的要好。具体代码实现如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if(root1==NULL) return root2;
if(root2==NULL) return root1;
TreeNode* node=new TreeNode();
node->val=root1->val+root2->val;
node->left=mergeTrees(root1->left,root2->left);
node->right=mergeTrees(root1->right,root2->right);
return node;
}
};
700.二叉搜索树中的搜索
题目链接:700. 二叉搜索树中的搜索 - 力扣(LeetCode)
这个题我刚上手没有考虑到这是一个二叉搜索树,直接在二叉树中序遍历的代码中加入了查找逻辑,也过了,但是时间复杂度较高。具体代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* ans=new TreeNode();
bool is=0;
void order(TreeNode* root,int val)
{
if(root==NULL) return;
if(is==1) return;
order(root->left,val);
order(root->right,val);
if(root->val==val)
{
is=1;
ans=root;
}
}
TreeNode* searchBST(TreeNode* root, int val) {
order(root,val);
if(is==0) return NULL;
return ans;
}
};
后来学习到二叉搜索树的特殊特性。二叉搜索树的左子树一定小于根节点,右子树一定大于根节点。所以对于二叉搜索树中序遍历的结果,一定是一个单调递增的数组。对于二叉搜索树,中序遍历也是较为推荐的做法。基于这个思路,我们在进行查找时会简单很多,当根节点小于目标值就往右子树递归,根节点大于目标值就往左子树递归。具体代码实现如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* order(TreeNode* root,int val)
{
if(root==NULL||root->val==val) return root;
TreeNode* result=new TreeNode();
if(val<root->val) result=order(root->left,val);
if(val>root->val) result=order(root->right,val);
return result;
}
TreeNode* searchBST(TreeNode* root, int val) {
TreeNode* result=order(root,val);
return result;
}
};
使用迭代法思路也是一样的。具体实现代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if(root==NULL) return NULL;
TreeNode* cur=root;
while(cur!=NULL)
{
if(val>cur->val) cur=cur->right;
else if(val<cur->val) cur=cur->left;
else return cur;
}
return NULL;
}
};
98.验证二叉搜索树
题目链接:98. 验证二叉搜索树 - 力扣(LeetCode)
刚拿到这个题目时,我的思想是使用中序遍历,对于根节点的处理逻辑是如果根节点大于左节点小于右结点就满足要求。但这个思路是错误的,对于下面这种情况,这样的判定思路就会输出错误的结果。
所以第一种思路是通过中序遍历的结果数组,判断是否是保持递增的,如果不是递增的说明不符合二叉搜索树的特性。具体代码实现如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> vec;
void order(TreeNode* root)
{
if(root==NULL) return;
order(root->left);
vec.push_back(root->val);
order(root->right);
}
bool isValidBST(TreeNode* root) {
vec.clear();
order(root);
for(int i=1;i<vec.size();i++)
{
if(vec[i-1]>=vec[i]) return false;
}
return true;
}
};
第二种思路是借助双指针,通过前一个指针存储上一次迭代遍历的值,并与当前的根节点值进行比较,如果上一次的值大于等于当前值,说明不符合二叉搜索树。这种思路既可以用递归实现,也可以用迭代法实现。代码实现如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> vec;
TreeNode* pre=NULL;
bool order(TreeNode* root)
{
if(root==NULL) return true;
bool left=order(root->left);
if(pre!=NULL&&root->val<=pre->val) return false;
pre=root;
bool right=order(root->right);
return left&&right;
}
bool isValidBST(TreeNode* root) {
vec.clear();
return order(root);;
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isValidBST(TreeNode* root) {
stack<TreeNode*> st;
TreeNode* pre=NULL;
TreeNode* cur=root;
if(root==NULL) return true;
while(cur!=NULL||!st.empty())
{
if(cur!=NULL)
{
st.push(cur);
cur=cur->left;
}
else
{
cur=st.top();
st.pop();
if(pre!=NULL&&cur->val<=pre->val) return false;
pre=cur;
cur=cur->right;
}
}
return true;
}
};
在写迭代法时有遇到一个问题,就是在进行中序遍历时,root节点是不能提前入栈的,不然会导致root节点入栈两次,导致答案出错。