算法day20|669. 修剪二叉搜索树、将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

算法day20|669. 修剪二叉搜索树、将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树

class Solution {
public:
    TreeNode* traversal(TreeNode* root, int low, int high)
    {
        if(root==nullptr)
        return nullptr;
        if(root->val<low)
        {
            TreeNode*right=traversal(root->right,low,high);
            return right;
        }
        if(root->val>high)
        {
            TreeNode*left=traversal(root->left,low,high);
            return left;
        }
        root->left=traversal(root->left,low,high);
        root->right=traversal(root->right,low,high);
        return root;
    }
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        return traversal(root,low,high);
    }
};

重点讲单层递归逻辑:首先,题目本质要求、返回值和逻辑三者是紧密结合的。题目要求返回最后树的根节点,那么我们的返回值肯定要选节点类型。再选择了返回值之后,我们移除节点的逻辑是什么样的呢?答:如果这个结点真的需要删除,那我们就用它可能成立的子树去替代,也就是说,这个结点被它的子树覆盖了。如果不是,该节点还是该节点。

本质就是检查是否“德不配位”:如果配位,你还在这个位置上;如果不配位,你就要下台,让你下面的子孙来顶替。当然,这子孙也要经过考验,所以实际是被考验后的子孙替代。

由于对当前结点的处理不需要借助孩子的信息,所以使用先序。当父亲确定好之后才能正常去遍历。

二叉树的修剪与删除的区别点在哪里?答:

  • 首先删除的核心操作在终止条件下进行,当遇到要删除的结点时,整个遍历过程其实已经结束了;而移除是对当前结点的处理。核心不同点终止条件里面是不能使用递归的,因为到这里递归一斤停止了;而对当前结点的处理是可以使用递归的。这也是判断是否区分两者的重要依据,所以使用和判断相辅相成。
  • 其次,

两者共同点:

  • 都是用root->left或者root->right来接收递归返回值,因为在每一次递归,结点都要经过审判,如果满足某种条件它就要被剔除或者替代,所以这是直接面向结点的、决定结点命运和生死的操作,所以直接用结点本身来接收。
  • 每一次返回的值是对当前结点的替代节点。可以是Null、可以是其他结点,也可以是它本身。这个和用root->left或者root->right来接收递归返回值是息息相关的,所以两者是统一考虑的。

08.将有序数组转换为二叉搜索树

class Solution {
public:
    TreeNode* traversal(vector<int>& nums,int left,int right)
    {
        if(left>right)
        return nullptr;
        int mid=(left+right)/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) {
        return traversal(nums,0,nums.size()-1);
    }
};

建立树肯定是从根节点往下建立的,所以关键是找到该插入数组中的哪一项。

我们在原数组中用两个指针,表示区间的边界(左闭右闭),通过计算,mid指针恰好指向要插入的元素。采用先序遍历,在当前结点处理完之后,左孩子用左区间,右孩子用右区间。

易错:

  • 终止条件,这里的终止条件不是数组的size为0,因为我们并没有对数组做任何的改变,我们只是用了两个指针来限定区间,所以终止条件肯定与两指针的位置有关。
  • 遵循循环不变量的原则,自始至终都遵循同一个区间标准,这里就是左闭右闭。

538.把二叉搜索树转换为累加树

class Solution {
public:
    int pre=0;
    void traversal(TreeNode*root)
    {
        if(root==nullptr)
        return;
        traversal(root->right);
        root->val+=pre;
        pre=root->val;
        traversal(root->left);
        return;
    }
    TreeNode* convertBST(TreeNode* root) {
        if(root==nullptr)
        return nullptr;
        traversal(root);
        return root;
    }
};

做这题需要巧劲,我一开始是从前往后加的,时间复杂度高不说,中间过程还非常繁琐,导致出错。而正确的思路是从后往前加,用pre指针记录之前的值,从而实现了边遍历边加。所以有时候按常规思维做题很费劲的时候,不妨停下来,换一种思路再想一遍。

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值