1.leetcode 669.修剪二叉搜索树
cpp
/**
* 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* trimBST(TreeNode* root, int low, int high) {
if(root==nullptr) return nullptr;
if(root->val<low){
TreeNode* right=trimBST(root->right,low,high);// 寻找符合区间[low, high]的节点
return right;
}
if(root->val>high){
TreeNode* left=trimBST(root->left,low,high);// 寻找符合区间[low, high]的节点
return left;
}
root->left=trimBST(root->left,low,high);// root->left接入符合条件的左孩子
root->right=trimBST(root->right,low,high);// root->right接入符合条件的右孩子
return root;
}
};
思路总结:如果不对递归有深刻的理解,这道题目还是有点难度的。因为二叉搜索树的特殊性,导致可能根节点的左孩子不符合条件,但是它的左孩子的右孩子可能符合条件,那如果一下子就把左孩子删除了,这样就会把左孩子的右孩子一起删除了,所以导致误删,所以我们还要再对左孩子的右孩子进行判断,那么右孩子的左孩子也是如此。
2.leetcode 108.将有序数组转换为二叉搜索树
cpp
/**
* 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://这里定义的区间就是左闭右闭,left和right都是数组的下标
TreeNode* traversal(vector<int>& nums,int left,int right){
if(left>right) return nullptr;//不合法区间
int mid=left+((right-left)/2);
TreeNode* root=new TreeNode(nums[mid]);//创建一个根节点
root->left=traversal(nums,left,mid-1);//构造左子树
root->right=traversal(nums,mid+1,right);//构造右子树
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
TreeNode* node=traversal(nums,0,nums.size()-1);
return node;
}
};
思路总结:因为我们这里规定的区间是左闭右闭,所以求mid的时候不能直接(left+right)/2,这样会导致下面的递归函数出错,最好的办法是left+((right-left)/2),这样就可以完美解决这个问题。这道题的解法有点像二分查找,先把有序数组分成左右两边,然后再进行操作,这样就可以构造二叉搜索树,但是也要知道二叉搜索树的特点,才知道为什么要用这个方法。
3.leetcode 538.把二叉搜索树转换为累加树
第一种解法:递归法
cpp
/**
* 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:
int pre=0;//记录前一个节点的数值
void traversal(TreeNode* current){//右中左遍历
if(current==nullptr) return;
traversal(current->right);//右
current->val+=pre;//中
pre=current->val;
traversal(current->left);//左
}
TreeNode* convertBST(TreeNode* root) {
pre=0;
traversal(root);
return root;
}
};
第二种解法:迭代法
cpp
/**
* 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:
int pre=0;//记录前一个节点的数值
void traversal(TreeNode* root){
stack<TreeNode*> st;//右中左 遍历顺序
TreeNode* current=root;
while(current!=NULL||!st.empty()){
if(current!=NULL){
st.push(current);
current=current->right;//右
}
else{
current=st.top();//中
st.pop();
current->val+=pre;
pre=current->val;
current=current->left;//左
}
}
}
TreeNode* convertBST(TreeNode* root) {
pre=0;
traversal(root);
return root;
}
};
思路总结:这道题的关键就是要清楚遍历顺序是什么,当然是右中左,这两种方法其实也不是很难,甚至可以看做是中序遍历的模板题,尤其是迭代法,就是中序遍历的模板,而这道题的遍历顺序可以看做反中序遍历,中序遍历是左中右,所以这道题还是比较简单的。
4.二叉树总结
(1)理论基础
二叉树的种类,存储方式,遍历方式,定义方式。这些在我第一篇二叉树的博客里面有具体的介绍。
(2)二叉树的遍历方式
深度优先遍历(前中后序遍历)、广度优先遍历(层序遍历,要用队列来模拟)。
(3) 求二叉树的属性
(4)二叉树的修改与构造
(5)求二叉搜索树的属性
(6)二叉树的公共祖先问题
(7)二叉搜索树的修改与构造
(8)最后总结
在二叉树题目选择什么遍历顺序是不少同学头疼的事情
涉及到二叉树的构造,无论普通二叉树还是二叉搜索树一定前序,都是先构造中节点。
求普通二叉树的属性,一般是后序,一般要通过递归函数的返回值做计算。
求二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。
注意在普通二叉树的属性中,我用的是一般为后序,例如单纯求深度就用前序。