力扣二叉树专题Ⅱ

在这里插入图片描述
来吧~继续奔跑!从左叶子之和开始。(本篇建议读完上篇力扣二叉树专题Ⅰ后服用)

二叉树属性

左叶子之和

LC 第404题

迭代法
int sumOfLeftLeaves(TreeNode* root) {
      stack<TreeNode*> st;
      int sum = 0;
      if(!root) return sum;
      st.push(root);
      while(!st.empty()){
          TreeNode* cur = st.top();
          st.pop();
          if(cur->left){
              TreeNode* tmp = cur->left;
              if(!tmp->left && !tmp->right) sum += tmp->val;
              st.push(tmp);
          }
          if(cur->right) st.push(cur->right);
      }
      return sum;
}
递归法

感觉还是没有很懂,写了一个第一个return就直接返回了。写的啥玩意?也叫递归?

确实嗷,好像都是左右结点用来递归(调用本函数),中间的结点用来执行一些操作(要么最简单的输出结果啊、要么压栈啊、入队啊、计算和啊什么的)而且此处要写最关键的逻辑。就比如本题,关键逻辑是:若该结点的左子不空,且该左子没有左子和右子,则找到了一个左叶子。(通过该结点是无法判断的,必须要通过父结点来判断)

int sumOfLeftLeaves(TreeNode* root) {
     if(!root) return 0;
     int leftNodes = sumOfLeftLeaves(root->left);//左
     int rightNodes = sumOfLeftLeaves(root->right);//右
     int midNodes = 0;//每次都要记得置零
     if(root->left && !root->left->left && !root->left->right) midNodes = root->left->val; //中
     return midNodes + leftNodes + rightNodes;//用该结点的左子+左子树的左子+右子树的左子=整棵树的左子之和
}

找树左下角的值

LC 第513题

迭代法
int findBottomLeftValue(TreeNode* root) {
      queue<TreeNode*> q;
      q.push(root);
      int res = root->val;
      while(!q.empty()){
          int s = q.size();
          for(int i = 0; i < s; i++){//每一层
              TreeNode* cur = q.front();
              q.pop();
              if(i == 0) res = cur->val;
              if(cur->left) q.push(cur->left);
              if(cur->right) q.push(cur->right);
          }
      }
      return res;
}
递归法

最深的一定是最下面那一层,怎么找到最左边的那个呢?无论中左右还是左右中都可以,只要保证左在前,就可以了。
相应的,如果要最深的一层的最右值,让右在前就可以了。
关键是把握好核心,就是找到最深的,更新层数和最左的结点值。

int maxDepth = INT_MIN;
int res;
void solve(TreeNode* cur, int leftDepth){
    if(cur->left) solve(cur->left, leftDepth+1);
    if(cur->right) solve(cur->right, leftDepth+1);
    if(cur && !cur->left && !cur->right && leftDepth > maxDepth){
        maxDepth = leftDepth;
        res = cur->val;
    }
}
int findBottomLeftValue(TreeNode* root) {
    solve(root, 0);
    return res;
}

路径总和

LC 第112题

递归法

纪念一下我独立写出的第一个正确的递归~(虽然很丑但是希望大家不要嫌弃QAQ)
虽然笨拙了点,但好歹是对的(不像之前那个一下就返回的假递归呜呜)

int target;
vector<int> v;
void solve(TreeNode* cur, int sum){
    if(cur && !cur->left && !cur->right){
        v.push_back(sum+cur->val);
    }
    if(cur->left) solve(cur->left, sum+cur->val);
    if(cur->right) solve(cur->right, sum+cur->val);
}
bool hasPathSum(TreeNode* root, int targetSum) {
    if(!root) return false;
    target = targetSum;
    solve(root, 0);
    for(int i = 0; i < v.size(); i++){
        if(targetSum == v[i]) return true;
    }
    return false;
}

再来看看大佬写的递归,那不比我简单许多?
直接传一个targetSum,若是减到零了就是正好;否则就是没有。

bool solve(TreeNode* cur, int sum){
    if(cur && !cur->left && !cur->right && sum == 0) return true;
    if(cur->left && solve(cur->left, sum - cur->left->val)) return true;
    if(cur->right && solve(cur->right, sum - cur->right->val)) return true;
    return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
    if(!root) return false;
    return solve(root, targetSum - root->val);
}

关于返回值的问题,总结是:如果要操作整棵树,就void;如果只需要找到其中一条路,就可以要返回值。
还有一个精简版(但是用了这么多方法好像也了解了这么写的缘故)

bool hasPathSum(TreeNode* root, int targetSum) {
     if(!root) return false;
     if(!root->left && !root->right && targetSum==root->val) return true;
     return hasPathSum(root->left, targetSum-root->val) || hasPathSum(root->right, targetSum-root->val);
}
迭代法

需要压栈的时候压一个pair,记得用node.first和node.second指代前后两个元素,别和->弄混了。
这个pair前一个是遍历到的结点,后一个是从根结点到该结点的val之和。

bool hasPathSum(TreeNode* root, int targetSum) {
    if(!root) return false;
    stack<pair<TreeNode*, int>> st;
    st.push(make_pair(root, root->val));
    while(!st.empty()){
        pair<TreeNode*, int> node = st.top();
        st.pop();
        if(!node.first->left && !node.first->right && node.second == targetSum) return true;
        if(node.first->left) st.push(make_pair(node.first->left, node.second+node.first->left->val));
        if(node.first->right) st.push(make_pair(node.first->right, node.second+node.first->right->val));
    }
    return false;
}

路径总和Ⅱ

LC 第113题

递归法

自己写的~(嘿嘿越来越像那么回事了)其实是照着二叉树的所有路径那题模仿的。

vector<vector<int>> res;
void solve(TreeNode* root, vector<int>& path, int sum){
    if(root && !root->left && !root->right && sum==0) res.push_back(path);
    if(root->left){
        int tmp = root->left->val;
        path.push_back(tmp);
        solve(root->left, path, sum-tmp);
        path.pop_back();
    }
    if(root->right){
        int tmp = root->right->val;
        path.push_back(tmp);
        solve(root->right, path, sum-tmp);
        path.pop_back();
    }
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
    if(!root) return res;
    vector<int> path;
    path.push_back(root->val);
    int sum = targetSum;
    solve(root, path, sum-root->val);
    return res;
}
迭代法

如果用栈的话,我想过了,要带三个参数:一个vector记录路径,一个当前结点,一个路径之和;但是如果不怕麻烦的话,路径之和可以用vector算出来,那么每次遍历到叶子结点都要算一遍(先这么写着吧作为初步思路)

不要忘了回溯呀(因为不是找到一个路径就停止,而是要找到所有的路径,那就不能停止,要回头)

vector<vector<int>> res;
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
    stack<TreeNode*> nodest;
    stack<vector<int>> pathst;
    if(!root) return res;
    nodest.push(root);
    vector<int> v;
    v.push_back(root->val);
    pathst.push(v);
    while(!nodest.empty()){
        TreeNode* cur = nodest.top(); nodest.pop();
        vector<int> path = pathst.top(); pathst.pop();
        if(!cur->left && !cur->right) {
            int sum = 0;
            for(int i = 0; i < path.size(); i++) sum += path[i];
            if(sum == targetSum) res.push_back(path);
        }
        if(cur->left){
            nodest.push(cur->left);
            path.push_back(cur->left->val);
            pathst.push(path);
            path.pop_back();
        }
        if(cur->right){
            nodest.push(cur->right);
            path.push_back(cur->right->val);
            pathst.push(path);
            path.pop_back();
        }
    }
    return res;
}

构造二叉树

从中序与后续遍历序列构造二叉树

LC 第106题

这里细想一下还是很熟悉的,因为曾经认认真真地没看题解想过,也敲过,所以总有些递归的手感在。
要注意的是,若要修改或者构造(总之就是改变)二叉树的时候,不要传递指针,直接写一个函数返回指针就好。
map是用来对应中序中值和位置的。(后面继续学习实现map的红黑树和实现unordered_map的哈希表)因为前/后序中根的位置好找(不是第一个就是最后一个)
还有就是最开始的那句范围判断别忘啦~

unordered_map<int, int> pos;
TreeNode* solve(int inleft, int inright, int posleft, int posright, vector<int> inorder, vector<int> postorder){
    if(inleft > inright || posleft > posright) return NULL;
    int rootvalue = postorder[posright];
    int rootpos = pos[rootvalue];
    TreeNode* root = new TreeNode(rootvalue);
    root->left = solve(inleft, rootpos-1, posleft, posleft+rootpos-inleft-1, inorder, postorder);
    root->right = solve(rootpos+1, inright, posleft+rootpos-inleft, posright-1, inorder, postorder);
    return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
    int s = inorder.size();
    if(s==0) return NULL;
    for(int i = 0; i < s; i++){
        pos[inorder[i]] = i;
    }
    return solve(0, s-1, 0, s-1, inorder, postorder);
}

从前序与中序遍历序列构造二叉树

LC 第105题

unordered_map<int, int> pos;
TreeNode* solve(int preleft, int preright, int inleft, int inright, vector<int> preorder, vector<int> inorder){
    if(preleft > preright || inleft > inright) return NULL;
    int rootvalue = preorder[preleft];
    int rootpos = pos[rootvalue];
    TreeNode* root = new TreeNode(rootvalue);
    root->left = solve(preleft+1, preleft+rootpos-inleft, inleft, rootpos-1, preorder, inorder);
    root->right = solve(preleft+rootpos-inleft+1, preright, rootpos+1, inright, preorder, inorder);
    return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    int s = preorder.size();
    for(int i = 0; i < s; i++) pos[inorder[i]] = i;
    return solve(0, s-1, 0, s-1, preorder, inorder);
}

ps:必须要有前序和后序之一,但是中序必须要有,因为没有中序就无法分割左右。

在这里插入图片描述

最大二叉树

LC 第654题

欸嘿,掌握了方法,写起来就很顺了!

unordered_map<int, int> pos;
TreeNode* solve(int numsleft, int numsright, vector<int> nums){
    if(numsleft > numsright) return NULL;
    int m = INT_MIN;
    for(int i = numsleft; i <= numsright; i++) m = max(m, nums[i]);
    int max_pos = pos[m];
    TreeNode* root = new TreeNode(m);
    root->left = solve(numsleft, max_pos-1, nums);
    root->right = solve(max_pos+1, numsright, nums);
    return root;
}
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
    int s = nums.size();
    if(s == 0) return NULL;
    for(int i = 0; i < s; i++) pos[nums[i]] = i;
    return solve(0, s-1, nums);
}

合并二叉树

LC 第617题

递归法
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
    if(!root1 && !root2) return NULL;
    if(!root1) return root2;
    if(!root2) return root1;
    TreeNode* root = new TreeNode();
    root->val = root1->val + root2->val;
    root->left = mergeTrees(root1->left, root2->left);
    root->right = mergeTrees(root1->right, root2->right);
    return root;
}

夭寿啦夭寿啦怎么递归这么容易就写出来了!看起来是掌握了秘法!(多刷题,你也可以!)就按照我的刷题顺序来(这都是前人走过的路摸出来的经验和便捷法门)

当然这题也可以迭代,每次把两棵树同位置的结点入队就行啦!把root2的那棵树叠加到root1的身上就好啦,还是写一下吧~

迭代法
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
    if(!root1) return root2;
    if(!root2) return root1;
    queue<TreeNode*> q;
    q.push(root1);
    q.push(root2);
    while(!q.empty()){
        TreeNode* cur1 = q.front(); q.pop();
        TreeNode* cur2 = q.front(); q.pop();
        cur1->val += cur2->val;
        if(cur1->left && cur2->left){
            q.push(cur1->left);
            q.push(cur2->left);
        }
        if(cur1->right && cur2->right){
            q.push(cur1->right);
            q.push(cur2->right);
        }
        if(!cur1->left && cur2->left) cur1->left = cur2->left;
        if(!cur1->right && cur2->right) cur1->right = cur2->right;
    }
    return root1;
}

哇哦!居然刷完了二叉树,接下来就是二叉搜索树啦!终不负所望掌握了递归呢!驾驭这种小妖精还是要多练呀,实践出真知!很短的一篇(其实也不短啦)献给在看的各位!嘿嘿,接下来就是二叉搜索树啦!

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值