0610刷题

0610刷题

LeetCode 654. 最大二叉树

LeetCode 654. 最大二叉树

自己写的

直接构造左右数组:

vector<int> leftVec(nums.begin(),nums.begin()+weizhi);
vector<int> rightVec(nums.begin()+weizhi+1,nums.end());

整体代码如下:

class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return traverse(nums); 
    }

    TreeNode* traverse(vector<int>& nums)
    {
        if(nums.size()==0) return nullptr;
        int rootValue=findMax(nums).first;
        TreeNode* root=new TreeNode(rootValue);
        int weizhi=findMax(nums).second;

        vector<int> leftVec(nums.begin(),nums.begin()+weizhi);
        vector<int> rightVec(nums.begin()+weizhi+1,nums.end());

        root->left=traverse(leftVec);
        root->right=traverse(rightVec);
        return root;
    }

    pair<int,int> findMax(vector<int>& nums)
    {
        int maxNum=INT_MIN;
        int weizhi=INT_MIN;
        for(int i=0;i<nums.size();++i)
        {
            if(nums[i]>maxNum)
            {
                maxNum=nums[i];
                weizhi=i;
            } 
        }
        return pair<int,int>(maxNum,weizhi);
    }
};

思路同LeetCode 106. 从中序与后序遍历序列构造二叉树

递归函数也可以直接用左右区间进行构造:

TreeNode* traversal(vector<int>& nums, int left, int right)

整体代码如下:

class Solution {
private:
    // 在左闭右开区间[left, right),构造二叉树
    TreeNode* traversal(vector<int>& nums, int left, int right) {
        if (left >= right) return nullptr;

        // 分割点下标:maxValueIndex
        int maxValueIndex = left;
        for (int i = left + 1; i < right; ++i) {
            if (nums[i] > nums[maxValueIndex]) maxValueIndex = i;
        }

        TreeNode* root = new TreeNode(nums[maxValueIndex]);

        // 左闭右开:[left, maxValueIndex)
        root->left = traversal(nums, left, maxValueIndex);

        // 左闭右开:[maxValueIndex + 1, right)
        root->right = traversal(nums, maxValueIndex + 1, right);

        return root;
    }
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return traversal(nums, 0, nums.size());//左闭右开,相当于区间是0~nums.size()-1.
    }
};

用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下标索引直接在原数组上操作,这样可以节约时间和空间上的开销。

LeetCode 98. 验证二叉搜索树

LeetCode 98. 验证二叉搜索树

方法1

利用性质:中序遍历下,输出的二叉搜索树节点的数值是有序序列。

class Solution {
private:
    vector<int> vec;
    void traversal(TreeNode* root) {
        if (root == NULL) return;
        traversal(root->left);
        vec.push_back(root->val); // 将二叉搜索树转换为有序数组
        traversal(root->right);
    }
public:
    bool isValidBST(TreeNode* root) {
        vec.clear(); // 不加这句在leetcode上也可以过,但最好加上
        traversal(root);
        for (int i = 1; i < vec.size(); i++) {
            // 注意要小于等于,搜索树里不能有相同元素
            if (vec[i] <= vec[i - 1]) return false;
        }
        return true;
    }
};

递归中序遍历将二叉搜索树转变成一个数组,然后只要比较一下,这个数组是否是有序的,注意二叉搜索树中不能有重复元素

!!!我们要比较的是 左子树所有节点小于中间节点,右子树所有节点大于中间节点。

不能单纯的比较左节点小于中间节点,右节点大于中间节点就完事了

错误示例如下:

//wrong answer!!!
if (root->val > root->left->val && root->val < root->right->val) {
    return true;
} else {
    return false;
}

方法2

class Solution {
public:
    //因为后台数据有int最小值测试用例,所以都把maxVal改成了longlong最小值
    long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值
    bool isValidBST(TreeNode* root) {
        if (root == NULL) return true;

        bool left = isValidBST(root->left);
        // 中序遍历,验证遍历的元素是不是从小到大
        if (maxVal < root->val) maxVal = root->val;
        else return false;
        bool right = isValidBST(root->right);

        return left && right;
    }
};

中序遍历,一直更新maxVal,一旦发现maxVal >= root->val,就返回false,注意元素相同时候也要返回false。

LeetCode 236. 二叉树的最近公共祖先

LeetCode 236. 二叉树的最近公共祖先

遇到这个题目首先想的是要是能自底向上查找就好了,这样就可以找到公共祖先了。

二叉树回溯的过程就是自底向上查找。

后序遍历就是天然的回溯过程,最先处理的一定是叶子节点。

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == q || root == p || root == NULL) return root;
        
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);

        if (left != NULL && right != NULL) return root;
        if (left == NULL && right != NULL) return right;
        else if (left != NULL && right == NULL) return left;
        else  { //  (left == NULL && right == NULL)
            return NULL;
        }
    }
};

如果left 和 right都不为空,说明此时root就是最近公共节点。这个比较好理解

如果left为空,right不为空,就返回right,说明目标节点是通过right返回的,反之依然

LeetCode 701. 二叉搜索树中的插入操作

LeetCode 701. 二叉搜索树中的插入操作
class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        //终止条件就是找到遍历的节点为null的时候,就是要插入节点的位置了,并把插入的节点返回。
        if (root == NULL) {
            TreeNode* node = new TreeNode(val);
            return node;
        }
        
        if (root->val > val) root->left = insertIntoBST(root->left, val);
        if (root->val < val) root->right = insertIntoBST(root->right, val);
        return root;
    }
};

LeetCode 450. 删除二叉搜索树中的节点

LeetCode 450. 删除二叉搜索树中的节点
class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if(root==nullptr) return root;
        if(root->val==key) 
        {
            if (root->left == nullptr && root->right == nullptr) return nullptr;
            else if (root->left == nullptr) return root->right;
            else if (root->right == nullptr) return root->left;
            else
            {
                TreeNode* cur = root->right; // 找右子树最左面的节点
                while(cur->left) 
                {
                    cur = cur->left;
                }
                cur->left = root->left; // 把要删除的节点(root)左子树放在cur的左孩子的位置
                root = root->right;     // 返回旧root的右孩子作为新root
                return root;
            }
        }

        if(root->val>key) root->left=deleteNode(root->left,key);
        if(root->val<key) root->right=deleteNode(root->right,key);
        return root;
    }
};
  • 确定单层递归的逻辑

这里就把二叉搜索树中删除节点遇到的情况都搞清楚。

有以下五种情况:

  • 第一种情况:没找到删除的节点,遍历到空节点直接返回了
  • 找到删除的节点
    • 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
    • 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
    • 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
    • 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。

LeetCode 669. 修剪二叉搜索树

LeetCode 669. 修剪二叉搜索树
class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        if (root == nullptr ) return nullptr;
        //如果root(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树符合条件的头结点。
        if (root->val < low) {
            TreeNode* right = trimBST(root->right, low, high); // 寻找符合区间[low, high]的节点
            return right;
        }
        //如果root(当前节点)的元素大于high的,那么应该递归左子树,并返回左子树符合条件的头结点。
        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;
    }
};

简化之后,如下:

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

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

LeetCode 538. 把二叉搜索树转换为累加树
class Solution {
private:
    //需要定义一个全局变量pre,用来保存cur节点的前一个节点的数值
    int pre=0; // 记录前一个节点的数值
    void traversal(TreeNode* cur) 
    { // 右中左遍历
        if (cur == NULL) return;
        traversal(cur->right);
        cur->val += pre;
        pre = cur->val;
        traversal(cur->left);
    }
public:
    TreeNode* convertBST(TreeNode* root) {
        pre = 0;
        traversal(root);
        return root;
    }
};

一个有序数组[2, 5, 13],求从后到前的累加数组,也就是[20, 18, 13]

从树中可以看出累加的顺序是右中左,所以我们需要反中序遍历这个二叉树,然后顺序累加就可以了

需要定义一个全局变量pre,用来保存cur节点的前一个节点的数值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值