Leetcode—二叉树(二)

第226题 翻转二叉树

解题思路:采用后续遍历,因为后续是左右根,即可从最下面开始,自下而上的交换左右子树。

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        //采用后序遍历
        //判断树不为空
        if(root == nullptr)
            return root;
        TreeNode* p = root;
        //开始迭代求解
        invertTree(p->left);
        invertTree(p->right);
        swap(p->left,p->right);
        return root;
    }
};

第101题 对称二叉树

解题思路:如何判断一个二叉树轴对称(镜像)呢?其实是相当于把左右子树看成两棵独立的树,对这两棵独立的树,自下而上的开始对比,要对两棵树进行后序遍历,但是后序遍历的顺序有区别,一棵是左右根,一棵是右左根,二者相等才能说明对称

class Solution {
public:
    //递归法
    bool comTrees(TreeNode* LTree,TreeNode* RTree)
    {
        //都是空结点
        if(LTree == nullptr && RTree == nullptr)
            return true;
        //一空一不空
        else if(LTree != nullptr && RTree == nullptr)
            return false;
        else if(LTree == nullptr && RTree != nullptr)
            return false;
        //都不空
        else if(LTree->val != RTree->val)
            return false;
        //都相等继续往下判断
        else
            return comTrees(LTree->left,RTree->right) && comTrees(LTree->right, RTree->left);;
        
    }
    //迭代法
    bool isSymmetric(TreeNode* root){
        //用栈存储“两棵树”的左右结点,然后出栈比较
        stack<TreeNode*> st;
        if(root == nullptr)
            return true;
        //先把根节点的左右子树压入栈
        st.push(root->left);
        st.push(root->right);
        while(!st.empty())
        {
            //出栈两个元素进行比较
            TreeNode* node_1=st.top();
            st.pop();
            TreeNode* node_2=st.top();
            st.pop();
            //若都是空结点,跳过本次循环开始下一次
            if(node_1==nullptr && node_2==nullptr)
                continue;
            if((!node_1 || !node_2) || node_1->val != node_2->val)
                return false;
            //若当前处于对称状态,继续向下判断
            st.push(node_1->left);
            st.push(node_2->right);
            st.push(node_1->right);
            st.push(node_2->left);
        }
        return true;
    }
    bool isSymmetric(TreeNode* root) {
        //如何判断一个二叉树轴对称(镜像)呢?其实是相当于把左右子树看成两棵独立的树
        //对这两棵独立的树,自下而上的开始对比,要对两棵树进行后序遍历
        //但是后序遍历的顺序有区别,一棵是左右根,一棵是右左根,二者相等才能说明对称
        if(root == nullptr)
            return true;
        TreeNode* root_1 = root->left;
        TreeNode* root_2 = root->right;
        return comTrees(root_1,root_2);
    }
};

第100题 相同的树

解题思路:同101题

class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        //迭代法
        if(p==nullptr && q==nullptr)
            return true;
        if(p==nullptr || q==nullptr)
            return false;
        stack<TreeNode*> st;
        st.push(p);
        st.push(q);
        while(!st.empty())
        {
            TreeNode* node_1 = st.top();
            st.pop();
            TreeNode* node_2 = st.top();
            st.pop();
            if(node_1==nullptr && node_2==nullptr)
                continue;
            if((!node_1 || !node_2)||(node_1->val != node_2->val))
                return false;
            
            st.push(node_1->left);
            st.push(node_2->left);
            st.push(node_1->right);
            st.push(node_2->right);
        }
        return true;
    }
};

第572题 另一棵树的子树

解题思路:同样是判断是否有相等子树,这里在遍历根树是借用了栈

class Solution {
public:
    //递归法求相同树
    bool isSametree(TreeNode* p,TreeNode* q)
    {
        if(p==nullptr && q==nullptr)//p,q都空
            return true;
        else if(p==nullptr || q==nullptr)//p或q其中一个不为空
            return false;
        else if(p->val != q->val)//p和q都不空
            return false;
        else 
            return isSametree(p->left,q->left) && isSametree(p->right,q->right);
    }
    bool isSubtree(TreeNode* root, TreeNode* subRoot) {
        //前序遍历root树
        stack<TreeNode*> st;
        st.push(root);
        while(!st.empty())
        {
            TreeNode* p = st.top();
            st.pop();
            if(p->val == subRoot->val)
            {
                bool res = isSametree(p,subRoot);
                //若当前结点相等但不是相等树,继续往下找找
                if(res == true)
                    return res;
            }
            if (p->right!=nullptr) st.push(p->right);
            if (p->left!=nullptr) st.push(p->left);
        }
        return false;
    }
};

第104题 二叉树最大深度

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root == nullptr)
            return 0;
        //前序遍历:自上而下求深度
        //后序遍历:自下而上求高度(后序遍历也可以求深度)
        //分别遍历左右子树,谁深就要谁
        int lefthigh = 1 + maxDepth(root->left);
        int righthigh =1 + maxDepth(root->right) ;
        int res = lefthigh>righthigh?lefthigh:righthigh;
        return res;
    }
};

第110题 平衡二叉树

解题思路:本质上还是求树的高度,若当前根节点左右子树高度差值大于1,就不是平衡二叉树。

class Solution {
public:
    int getDeepth(TreeNode* root)
    {
        if(root==nullptr)
            return 0;
        int Ldeep = getDeepth(root->left) +1;
        int Rdeep = getDeepth(root->right) + 1;
        
        return Ldeep>Rdeep?Ldeep:Rdeep;
    }
    bool isBalanced(TreeNode* root) {
        //递归解法
        //以根节点为起始,若当前左右子树高度差值大于1,就不是二叉树
        if(root==nullptr)
            return true;
        int leftDeep = 0;
        int rightDeep = 0;
        leftDeep = getDeepth(root->left);
        rightDeep = getDeepth(root->right);

        if(abs(leftDeep-rightDeep)>1)
            return false;
        else
            return isBalanced(root->left) && isBalanced(root->right);
    }
};

第111题 二叉树的最小深度

class Solution {
public:
    int minDepth(TreeNode* root) {
        //采用后序遍历,找最小深度
        if(root == nullptr)
            return 0;
        if(root->left != nullptr && root->right != nullptr)
        {
            int lefthigh = minDepth(root->left) + 1;
            int righthigh = minDepth(root->right) + 1;
            return lefthigh<righthigh?lefthigh:righthigh;
        }
        else if(root->left == nullptr && root->right != nullptr)
            return 1 + minDepth(root->right);
        else if(root->left != nullptr && root->right == nullptr)
            return 1 + minDepth(root->left);
        else
            return 1;
    }
};

第222题 完全二叉树的节点个数

解题思路:一棵完全二叉树可以看成许多个子满二叉树组成的,因此,若当前二叉树不是满二叉树,则递归找下面的满二叉树(单个结点也是一个满二叉树),满二叉树的结点数为2^deep - 1,若当前不是满二叉树,分别递归左右子树,在左右递归返回时,还要加上当前的根节点。具体思路如下:

class Solution {
public:
    int countNodes(TreeNode* root) {
        if(root == nullptr)
            return 0;
        //分别求左侧右侧深度
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int leftDeep = 0;
        int rightDeep = 0;
        //开始求左子树
        while(left!=nullptr)
        {
            left = left->left;
            leftDeep++;
        }
        //再求右子树
        while(right!=nullptr)
        {
            right = right->right;
            rightDeep++;
        }
        //若左右子树深度相等,则说明当前子树就是一个完全二叉树
        if(leftDeep == rightDeep)
            return pow(2,leftDeep+1) - 1;
        //若左右子树深度不等,说明当前子树不是一个完全二叉树,继续向下找完全二叉树
        return countNodes(root->left) + countNodes(root->right) + 1;
    }
};

第257题 二叉树所有路径

解题思路:首先我们要先序遍历把路径记录下来,当走到第一条路径结尾时,需要回溯,回退到当前结点的根节点,然后进入另一个路径。这里使用了回溯思想。

class Solution {
public:
    void PathTravel(TreeNode* root,vector<int>& path,vector<string>& res)
    {
        //因为最先需要存储的是根节点,所以需要先序遍历
        path.push_back(root->val);
        //若当前结点是叶子节点,递归出口
        if(root->left==nullptr && root->right==nullptr)
        {
            //"打印当前路径",最后一个结点先不打印
            string sp;
            int i;
            for(i = 0;i<path.size()-1;i++)
            {
                //字符串直接相加就是拼接
                sp += to_string(path[i]);//to_string(int)是将int类型转换成字符串类型
                sp += "->";//一个数字后面跟着一个“->”
            }
            //最后一个结点单独加
            sp += to_string(path[i]);
            //将当前路径存入结果中
            res.push_back(sp);
            return;
        }
        //若还没有到达叶子节点,继续递归
        if(root->left)
        {
            PathTravel(root->left,path,res);
            path.pop_back();//当前左子树遍历完,把左子树弹出,要开始遍历右子树,这就是回溯
        }
        if(root->right)
        {
            PathTravel(root->right,path,res);
            path.pop_back();
        }
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        //递归加回溯
        //定义存储结果的容器
        vector<string> res;
        //存储当前路径
        vector<int> path;
        if(root==nullptr)
            return res;
        //开始递归遍历
        PathTravel(root,path,res);
        return res;
    }
};

第404题 左叶子之和

给定二叉树的根节点 root ,返回所有左叶子之和。

解题思路:后序遍历,关键在于如何确定左叶子。

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        //后序遍历,只找左孩子
        if (root == nullptr)
            return 0;
        //只有一个结点,也返回0
        if (root->left == nullptr && root->right == nullptr)
            return 0;
        int leftnode = sumOfLeftLeaves(root->left);
        //如何判断当前结点有左叶子?
        //该结点的左孩子不为空,并且这个左孩子的左右孩子都是空
        if (root->left && !root->left->left && !root->left->right)
            leftnode = root->left->val;
        //找完左子树再找右子树
        int right_leftnode = sumOfLeftLeaves(root->right);
        return leftnode+right_leftnode;
    }
};

第513题 找树左下角的值

解题思路:层序遍历,每次遍历从右往左遍历,这样遍历到的最后一个结点就是最左结点

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        queue<TreeNode*> qe;
        TreeNode* p = root;
        qe.push(p);
        vector<int> res;
        while(!qe.empty())
        {
            int num = qe.size();
            for(int i = 0;i<num;i++)
            {
                p = qe.front();
                res.push_back(p->val);
                qe.pop();
                if(p->right) qe.push(p->right);
                if(p->left) qe.push(p->left);
            }
        }
        return res.back();
    }
};

第112题 路径总和

解题思路:求和不好做,可以转换成找叶子节点是否等于“目标值-遍历过结点和”,若相等,即返回true。

class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root == nullptr)
            return false;
        //当前是叶子结点
        if(root->left == nullptr && root->right==nullptr)
        {
            if(targetSum == root->val)
                return true;
            else
                return false;
        }
        //若不是叶子节点,向下迭代找叶子节点
        //注意此处用或运算,即不管是左子树还是右子树,找到即可
        return (hasPathSum(root->left,targetSum-root->val) || hasPathSum(root->right,targetSum-root->val));
    }
};

第106题 从中序与后序遍历构造二叉树

class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(postorder.size() == 0) return NULL;
        //先看后续遍历确定根节点
        int val = postorder.back();
        TreeNode* root = new TreeNode(val);

        //若当前是叶子结点,直接返回
        if(postorder.size()==1) return root;

        //根据根节点划分新的左右子树结点
        //子树的中序遍历
        //index指向的是根节点在中序数组中位置
        int index;
        for (index = 0;index<inorder.size();index++)
        {
            if (inorder[index] == val)
                break;
        }
        
        vector<int> inorderleft(inorder.begin(), inorder.begin() + index);
        vector<int> inorderright(inorder.begin() + index + 1, inorder.end());

        //子树的后序遍历
        vector<int> postleft(postorder.begin(), postorder.begin() + inorderleft.size());
        vector<int> postright(postorder.begin() + inorderleft.size(), postorder.end() - 1);
        //开始构建左右子树
        root->left = buildTree(inorderleft, postleft);
        root->right = buildTree(inorderright, postright);
        return root;
    }
};

第654题 最大二叉树

整体思路同上一题

class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        if (nums.size() == 0)
        return NULL;
        //找最大值
        int max_val = -1;
        int max_index;
        for (int i = 0; i < nums.size(); i++)
        {
            if (nums[i] > max_val)
            {
                max_val = nums[i];
                max_index = i;
            }
        }
        //新建节点
        TreeNode* root = new TreeNode(max_val);
        //若当前结点是叶子节点,构造完就退出
        if (nums.size() == 1)
            return root;

        //根据叶子节点划分左右子树
        vector<int> leftnum(nums.begin(), nums.begin() + max_index);
        vector<int> rightnum(nums.begin() + max_index + 1, nums.end());

        //开始构造左右子树
        root->left = constructMaximumBinaryTree(leftnum);
        root->right = constructMaximumBinaryTree(rightnum);

        return root;
    }
};

第617题 合并二叉树

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if(root2==nullptr)
            return root1;
        if(root1==nullptr)
            return root2;
        
        root1->val = root1->val+root2->val;
        //开始构建左右子树    
        root1->left = mergeTrees(root1->left,root2->left);
        root1->right = mergeTrees(root1->right,root2->right);

        return root1;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值