算法day14|110.平衡二叉树 (优先掌握递归)、 二叉树的所有路径(优先掌握递归)、404.左叶子之和 (优先掌握递归)、222.完全二叉树的节点个数(优先掌握递归)

算法day14|110.平衡二叉树 (优先掌握递归)、 二叉树的所有路径(优先掌握递归)、404.左叶子之和 (优先掌握递归)、222.完全二叉树的节点个数(优先掌握递归)

  • 110.平衡二叉树 (优先掌握递归)
  • 257. 二叉树的所有路径(优先掌握递归)
  • 404.左叶子之和 (优先掌握递归)
  • 222.完全二叉树的节点个数(优先掌握递归)

110.平衡二叉树 (优先掌握递归)

我用我原来的思路去做,发现运行不了,目前也没有找到问题…

class Solution {
public:
    bool travel(TreeNode*root,int &count)
    {
        if(root==nullptr)
        return false;
        count++;
        int count1=count,count2=count;
        travel(root->left,count1);
        travel(root->right,count2);
        if(count1-count2>1||count2-count1>1)
        return false;
        count=count1>count2?count1:count2;
        return true;
    }
    bool isBalanced(TreeNode* root) {
        int count=0;
        if(root!=nullptr)
        return travel(root,count);
    }
};

因为求深度:从上到下去查 所以需要前序遍历,而高度:从下到上去查,所以只能后序遍历

但是104.二叉树的最大深度 (opens new window)用的是后序遍历。那是因为代码的逻辑其实是求的根节点的高度,而根节点的高度就是这棵树的最大深度,所以才可以使用后序遍历。

正确的代码:

class Solution {
public:
    int getHeight(TreeNode*root)
    {
        if(root==nullptr)
        return 0;
        int left=getHeight(root->left);
        if(left==-1)  return -1;
        int right=getHeight(root->right);
        if(right==-1) return -1;
        int result;
        if(abs(left-right)>1)
        result= -1;
        else
        result=1+(left>right?left:right);
        return result;
    }
    bool isBalanced(TreeNode* root) {
        if(root==nullptr)
        return true;
        if(getHeight(root)==-1)
        return false;
        else
        return true;
    }
};

总体思路(递归):

  • 返回值为int,原因是我们需要知道每个结点的高度,用int就不需要引入count了,让代码更加清晰
  • 终止条件(2个):
    1. null,返回0;
    2. 根据题目要求,发现不符合平衡二叉树的要求,返回-1;
  • 单层递归:由于我们需要先知道孩子的信息(即高度),我们才能确定当前节点的高度。所以我们使用后序遍历。当获取孩子的信息之后,如果abs>1,要返回-1;反之,说明在结点的统治下全部都是平衡二叉树。那么需要返回这个结点的高度,即左右孩子中的最大高度+1;

需要注意的是,当出现一个结点不满足平衡二叉树时,它上面的结点就都不满足了。所以在后序遍历的时候,如果孩子节点返回的时-1,那么父节点也要直接返回-1;

代码细节:

  1. 绝对值函数abs(),最大值函数max()
  2. 空树也是平衡二叉树
  3. 变量在定义的时候不一定要赋值,在使用前被赋值即可。所以可以直接写int result,后面没有去使用result,只有对result的赋值。
  4. 注意运算的优先级:result=1+(left>right?left:right),这里的三元运算符要加括号或者直接使用max()

257. 二叉树的所有路径(优先掌握递归)

class Solution {
public: 
    void traversal(TreeNode*root,vector<int>&path,vector<string>& result)
    {
        path.push_back(root->val);
        if(root->left==nullptr&&root->right==nullptr)
        {
            string str;
            for(int i=0;i<path.size()-1;i++)
            {
                str+=to_string(path[i])+"->";
            }
            str+=to_string(path[path.size()-1]);
            result.push_back(str);
            return;
        }
        if(root->left)
        {
            traversal(root->left,path,result);
            path.pop_back();
        }
        if(root->right)
        {
            traversal(root->right,path,result);
            path.pop_back();
        }
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<int> path;
        vector<string> result;
        if(root!=nullptr)
        traversal(root,path,result);
        return result;
    }
};

总体思路(递归):

  • 参数:vector result是最后需要的结果,而vector是作为缓冲的,先把这些值放到整数型数组里面,然后放完之后统一转化成字符串型数组

  • **终止条件:**这道题比较特殊,它是在当该节点为叶子结点的时候终止。终止的时候,这条路径的整数型数组已经放满了。它会完成一个非常重要的操作:把整数型数组转化成字符型数组。这个我愿意定义为终止条件下的特殊行为(这些行为只有在终止的时候才会执行)

  • 单层递归:

    • 为了最容易地形成这样的路径(由父—>孩子这样的顺序),显然是采用先序遍历,先存放父,再存放孩子,这样在整数型数组里的顺序也是和字符串性别数组的顺序是一致的。
    • 对于当前结点,我们只需要将结点的值存入整数型数组即可。为了和叶节点的逻辑统一,我们把这个操作放在终止条件前面。
    • 对于孩子结点,为了避免空指针异常的问题(在叶子节点的时候可能会发生),在递归之前需要判断该节点是否为空。还有最为重要的是,在左孩子的递归结束后,要将整数型数组里面的元素抛出一个,这就是大名鼎鼎的回溯.

注意,不是说左孩子刚把自己放入数组就立刻抛出,那不放个寂寞…,所以正确的理解是:当左孩子的整个递归全部执行完之后,也就是在它自己的递归里面还要向下递归呢,直到无法递归为止,这才算结束。所以这里的左孩子的含义就是左子树,当当前结点的左子树全部递归完、回溯完了之后,才轮到当前结点的左孩子作回溯

代码细节:

  1. to_string(整数型)函数,可将整数型转化字符串,最后返回的字符串形式
  2. 终止条件下的return 千万不能忘了,否则递归就没有出口了,结束不了了

404.左叶子之和 (优先掌握递归)

掌握了上面的题目之后,这道题就小菜一碟了,具体代码如下:

class Solution {
public:
    void traversal(TreeNode*root,vector<int>& vec,bool flag)
    {
        if(root->left==nullptr&&root->right==nullptr&&flag==true){
            vec.push_back(root->val);
            return;
        }
        if(root->left)
        {
            flag=true;
            traversal(root->left,vec,flag);
        }
        if(root->right)
        {
            flag=false;
            traversal(root->right,vec,flag);
        }
    }
    int sumOfLeftLeaves(TreeNode* root) {
        vector<int> vec;
        bool flag=false;
        if(root!=nullptr)
        traversal(root,vec,flag);
        int count=0;
        for(int i=0;i<vec.size();i++)
        {
            count+=vec[i];
        }
        return count;
    }
};

总体思路:同样以叶节点为终止条件,终止行为是将该左叶结点的值存入vector,非常简单。

222.完全二叉树的节点个数(优先掌握递归)

这题依旧小菜一碟,具体代码如下:

class Solution {
public:
    int traversal(TreeNode*root)
    {
        if(root==nullptr)
        return 0;
        int left=traversal(root->left);
        int right=traversal(root->right);
        int result=1+left+right;
        return result;
    }
    int countNodes(TreeNode* root) {
        if(root==nullptr)
        return 0;
        else
        {
            return traversal(root);
        }
    }
};

总体思路:后序遍历,因为需要先利用孩子节点的信息。可以理解为从下往上一个一个加。

你可能感兴趣的:(算法,数据结构,c++,leetcode)