day 16

day 16|完全二叉树的节点个数 路径综合 从中序与后序遍历序列构造二叉树

222.完全二叉树的节点个数

222.完全二叉树的节点个数 | 代码随想录

笔记

利用完全二叉树的特性,如果一个树是满二叉树,他的节点个数能够根据他的最大深度求出。

怎么判断一个树是否为满二叉树?(在已知这个树肯定是完全二叉树的情况下)他的最左端的节点和最右端的节点深度相同。

1.递归传入参数和输出参数:传入参数为根节点、输出参数为总节点个数

2.截止条件:碰到nullptr直接返回0;如果是满二叉树,直接返回2^n-1(n是深度);

3.单层递归逻辑:向左向右递归求得左右子树的节点个数;在中间节点返回该树的总结点个数(左+右+1);

实操出现问题

位操作优先级低于加减法

2<<leftdepth-1等价于2 << (leftdepth - 1)

为了保证不移动负数位,应该加括号(2<<leftdepth)-1;

代码/比较

class Solution {
public:
    int countNodes(TreeNode* root) {
        //截止条件:1.null 2.满二叉树
        if(root==nullptr) return 0;
        int leftdepth=0;
        int rightdepth=0;
        TreeNode* root_left=root;
        while(root_left->left)
        {
            root_left=root_left->left;
            leftdepth++;
        }
        TreeNode* root_right=root;
        while(root_right->right)
        {
            root_right=root_right->right;
            rightdepth++;
        }
        if(rightdepth==leftdepth)
            return (2<<leftdepth)-1;
        //单层递归逻辑:
        return (countNodes(root->left)+countNodes(root->right)+1);
    }
};

112. 路径总和

112. 路径总和 | 代码随想录

笔记:

1.传入参数和输出参数:输出true/false,传入根节点、对比值;

2.截止条件:如果是叶子节点并且对比值为0;返回true;

3.单层递归逻辑:分别向左右遍历,用对比值减去当前节点的val值传入下一个递归,如果返回的是true则向上返回true;

实操出现问题:

对于叶子节点应该先减去自己的值来对比。

代码:

class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        //截止条件:如果是叶子节点并且对比值为0,返回true;如果找到叶子但是对比值不为0,返回false
        if(root==nullptr) return false;
        if(root->left==nullptr&&root->right==nullptr&&targetSum-root->val==0) return true;
        if(root->left==nullptr&&root->right==nullptr&&targetSum-root->val!=0) return false;
        //单层循环逻辑:分别向左右遍历,用对比值减去当前节点的val值传入下一个递归,如果返回的是true则向上返回true;
        if(root->left)
        {
            if(hasPathSum(root->left,targetSum-root->val))
                return true;
        }
        if(root->right)
        {
            if(hasPathSum(root->right,targetSum-root->val))
                return true;
        }
        return false;
    }
};

113.路径总和2

自己的思考:

1.传入参数:root和对比值。输出参数:无。但是要用全局变量,一个一维数组,一个二维数组,一维数组用于存放当前路径,二维数组用于存放结果路径。

2.截止条件:如果是叶子节点并且对比值为0,将当前一维数组push_back到二维数组中,return;如果不为0,不做任何处理,return即可。

3.单层迭代逻辑:依次向左右子树进行递归求对比值,同时将下一个路径放入一维数组中

代码:

class Solution {

public:
    vector<int> result_1;
    vector<vector<int>> result_2;
    void traversal(TreeNode* root,int targetSum)
    {   
        //截止条件:如果是叶子节点并且对比值为0,将当前一维数组`push_back`到二维数组中,`return`;如果不为0,不做任何处理,`return`即可。
        if(root->left==nullptr&&root->right==nullptr&&targetSum-root->val==0)
        {
            result_2.push_back(result_1);
            return;
        }
        if(root->left==nullptr&&root->right==nullptr&&targetSum-root->val!=0)
            return;
        //单层递归逻辑:依次向左右子树进行递归求对比值,同时将下一层路径放入一维数组中
        if(root->left)
        {
            result_1.push_back(root->left->val);
            traversal(root->left,targetSum-root->val);
            result_1.pop_back();
        }
        if(root->right)
        {
            result_1.push_back(root->right->val);
            traversal(root->right,targetSum-root->val);
            result_1.pop_back();
        }
        return ;
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        result_2.clear();
        if(root==nullptr) return result_2;
        //先把现在的路径传入result_1
        result_1.push_back(root->val);
        traversal(root,targetSum);
        return result_2;
    }
};

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

  • 第一步:如果数组大小为零的话,说明是空节点了。
  • 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
  • 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
  • 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
  • 第五步:切割后序数组,切成后序左数组和后序右数组
  • 第六步:递归处理左区间和右区间

中间切割数组的时候要注意循环不变量,即按照一个规则进行切割。

代码(明天补上):

class Solution {
public:
    //传入参数:中序数组和后续数组  输出参数:根节点
    TreeNode* traversal(vector<int>& inorder,vector<int>& postorder)
    {
        //截止条件:如果后序数组为空(因为先切后序数组),则返回空节点;创建中间节点;如果碰到叶子节点,则返回当前的节点;
        if(postorder.size()==0) return nullptr;
        int val=postorder[postorder.size()-1];//后序遍历最后一个一定是中节点
        TreeNode* root=new TreeNode(val);
        //if(postorder.size()==1) return root;
        //每层递归的逻辑:得到左子树的中序和后序数组、右子树的中序和后序数组;再依次遍历左右子树
        //找中序数组的分割点
        int index=0;
        for(;index<inorder.size();index++)
        {
            if(inorder[index]==val)
                break;
        }
        //将中序数组分割为左右子树的中序数组,注意左闭右开;
        vector<int> left_inorder(inorder.begin(),inorder.begin()+index);
        vector<int> right_inorder(inorder.begin()+index+1,inorder.end());
        //将后序数组分割为左右子树的后序数组,注意左闭右开;
        postorder.resize(postorder.size()-1);
        vector<int> left_postorder(postorder.begin(),postorder.begin()+index);
        vector<int> right_postorder(postorder.begin()+index,postorder.end());
        //再依次遍历左右子树
        root->left = traversal(left_inorder, left_postorder);
        root->right = traversal(right_inorder, right_postorder);
        return root;
    } 
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) return NULL;
        return traversal(inorder, postorder);
    }
};

1

posted @ 2026-01-29 20:58  欧尼酱ovo  阅读(7)  评论(0)    收藏  举报