【C++编程能力提升】

一、654 最大二叉树

题目链接:654 最大二叉树

核心:利用前序遍历递归构造二叉树(通常构造树都采用前序遍历)
第一,确定递归函数的参数和返回值:参数是存储元素的数组,返回值是构造后树的根节点;另外切割数组需额外定义新的数组,导致效率降低,因此使用下标直接在原数组上操作,那么参数还需要构造树的元素数组的区间;
第二,确定终止条件:区间为空即无节点元素,则返回nullptr;(注意:判断区间为空是因为单层递归逻辑中是可能存在空节点的)
第三,确定单层递归的逻辑:
首先找到数组中的最大值及其所处的下标(其实知道下标也知道最大值了),以该最大值构造根节点root,以此下标对数组分成左、右子树;
然后,利用左区间递归构造左子树;以及利用右区间递归构造右子树。
注意:区间要保证循环不变量,即所有区间都保持左闭右开或左闭右闭。

    //递归函数,nums区间是[left,right),返回根节点root
    TreeNode* traversal(vector<int>& nums,int left,int right)
    {
        //1.区间为空,即无节点,返回nullptr
        if(left>=right)
            return nullptr;
        //2.寻找nums最大值所在索引,构造root
        int maxIndex=left;  
        for(int i=left+1;i<right;++i)
        {
            if(nums[i]>nums[maxIndex])
                maxIndex=i;
        }
        TreeNode* root=new TreeNode(nums[maxIndex]);
        //3.分割左右区间,递归构造左右子树,左区间:[left,maxIndex),右区间:[maxIndex+1,right)
        root->left=traversal(nums,left,maxIndex);
        root->right=traversal(nums,maxIndex+1,right);
        return root;
    }
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return traversal(nums,0,nums.size());   //注意区间是左开右闭
    }

二、617 合并二叉树

题目链接:617 合并二叉树

核心:对两棵树的同一位置进行相同操作
(1)迭代法,类似层序遍历:借助队列,先将两棵树的根节点都入队,从队列中取出2个节点元素后,两节点值累加到节点1上;然后在两棵树的当前节点的左孩子都不为空时,进行入队操作,以及右孩子都不为空时也进行入队操作;而在树1的左孩子或右孩子为空,但树2的左孩子或右孩子不为空时,直接将树2的左孩子或右孩子赋值给树1的左孩子或右孩子;最后返回树1。
(2)递归法:采用前序遍历(中左右),对中的处理是2个节点值累加到树1上,然后对左子树和右子树进行递归处理。

   TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        //递归法:前序遍历,中左右
        if(!root1) return root2;
        if(!root2) return root1;
        root1->val +=root2->val;    //【中】
        root1->left=mergeTrees(root1->left,root2->left);    //左
        root1->right=mergeTrees(root1->right,root2->right); //右
        return root1;

        /*
        //迭代法,类似层序遍历
        if(!root1) return root2;
        if(!root2) return root1;
        queue<TreeNode*> que;
        que.push(root1);
        que.push(root2);
        while(!que.empty())
        {
            //从队列取出两个树的节点
            TreeNode* node1=que.front();
            que.pop();
            TreeNode* node2=que.front();
            que.pop();
            node1->val+=node2->val; //一定不为空,两个节点值相加,仍在root1这棵树
            if(node1->left && node2->left)
            {//node1和node2的左孩子都不为空时加入队列
                que.push(node1->left);
                que.push(node2->left);
            }
            if(node1->right && node2->right)
            {//右孩子都不为空时加入队列
                que.push(node1->right);
                que.push(node2->right);
            }
            if(!node1->left && node2->left)
                node1->left=node2->left;    //node1左孩子为空,node2左孩子不为空,赋值给node1
            if(!node1->right && node2->right)
                node1->right=node2->right;  //node1右孩子为空node2右孩子不为空,赋值给node1
        }
        return root1;   //最后返回root1,虽然一直对node1处理,但node1是root1的根节点
        */
    }

三、700 二叉搜索树中的搜索

题目链接:700 二叉搜索树中的搜索

核心:明确二叉搜索树是根节点的左孩子都小于根节点,且右孩子都大于根节点,因此中序遍历的元素一定是从小到大,且不存在重复的元素
(1)迭代法:只要当前节点不为空,则循环遍历,循环处理时需根据当前节点值与val的大小确定对左子树进行遍历还是对右子树进行遍历;
(2)递归法:
首先,递归函数的参数是根节点和待搜索值val,返回值是与val相等的节点;
其次,终止条件是:若root为空,或者root值与val相等(已找到此节点),都需要返回root;
最后,单层递归处理时,需根据当前节点值与val的大小确定搜索左子树还是右子树。

    TreeNode* searchBST(TreeNode* root, int val) {
    //递归法:
    if(!root || root->val == val)
        return root;    //要么为空要么找到val节点,都返回此时root
    TreeNode* res=nullptr;  //返回的节点
    if(root->val > val)
        res=searchBST(root->left,val);  //左子树搜索,如果找到了就返回res
    else if(root->val < val)
        res=searchBST(root->right,val); //右子树搜索
    return res; 

    /*
    //迭代法:
        while(root)
        {//只要当前节点不为空就需要继续搜索
            if(root->val > val)
                root=root->left;    
            else if(root->val <val)
                root=root->right;
            else 
                return root;    //root->val == val,找到了,返回此时的root
        }
        return nullptr; //遍历所有节点都没有找到val
    */
    }

四、98 验证二叉搜索树

题目链接:98 验证二叉搜索树

核心:明确二叉搜索树的中序遍历数组一定是从小到大的有序数组,且不存在重复元素。
(1)利用中序遍历得到其有数组,判断该数组所有元素是否都是按照从小到大排列,一旦出现前一个元素大于等于当前元素值,则说明不是二叉搜索树;
(2)同样利用中序遍历,但无需构造数组,直接在遍历每个节点时与前一个节点相比较,若前一个节点值大于等于当前节点值,则返回false;否则说明该节点是符合条件的,需要更新前一个节点(更新到当前节点),继续判断下一个节点。
第二种思想可以通过递归法和迭代法分别实现,递归法的终止条件是当前节点为空时返回true,单层递归逻辑是先左在处理中最后是右,处理中时将当前节点与前一个节点进行比较;迭代法需借助栈来实现(目前理解不够深入)。

    vector<int> res;
    void traversal(TreeNode* node)
    {//中序遍历:左中右
        if(!node) 
            return;
        traversal(node->left);
        res.push_back(node->val);   //得到中序遍历的数组
        traversal(node->right);
    }

    bool isValidBST(TreeNode* root) {
    //中序遍历数组必须是从小到大,且不存在重复元素
        traversal(root);
        for(int i=1;i<res.size();++i)
        {
            if(res[i]<=res[i-1])
                return false;   //一旦发现前一个元素之大于等于当前元素,说明不是二叉搜索树
        }
        return true;
    }
    bool isValidBST(TreeNode* root) {
    //迭代法:中序遍历,左中右,借助栈
        stack<TreeNode*> stk;
        TreeNode* cur=root;     //记录当前节点
        TreeNode* pre=nullptr;  //记录前一个节点
        while(cur || !stk.empty())
        {
            if(cur)
            {//当前节点不为空,需入栈,并向左遍历
                stk.push(cur);
                cur=cur->left;  //左
            }
            else
            {//cur为空,说明左边遍历结束,此时stk栈顶元素是最左边的元素
                cur=stk.top();      //【中】
                stk.pop();
                if(pre && cur->val <= pre->val)
                    return false;
                pre=cur;    //更新前一个节点

                cur=cur->right;     //右【不能遗漏这一步!】
            }
        }
        return true;    //遍历结束都没有发现前一个节点值大于等于当前节点值的节点

    /*
    //递归法:中序遍历,左中右
        if(!root)
            return true;
        bool left=isValidBST(root->left);
        if(pre && pre->val >= root->val)
            return false;   //一旦前一个节点值大于等于当前节点值,则返回false
        pre=root;   //更新前一个节点
        bool right=isValidBST(root->right);
        return left && right;   //只有左、右子树都符合二叉搜索树
        */
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值