leetcode算法刷题的第十八天

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)最后总结

在二叉树题目选择什么遍历顺序是不少同学头疼的事情

涉及到二叉树的构造,无论普通二叉树还是二叉搜索树一定前序,都是先构造中节点。

求普通二叉树的属性,一般是后序,一般要通过递归函数的返回值做计算。

求二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。

注意在普通二叉树的属性中,我用的是一般为后序,例如单纯求深度就用前序。