代码随想录算法训练营第19天-104.二叉树的最大深度-111.二叉树的最小深度-222.完全二叉树的节点个数

104.二叉树的最大深度 (优先掌握递归)

这道题其实昨天写了,当时说是层序遍历做,但是层序和递归我都做了

1.层序遍历

int maxDepth(TreeNode* root) {
    int depth = 0;
    queue<TreeNode*> q;

    if (root) q.push(root);
    while (!q.empty())
    {
        depth++;

        int size = q.size();
        while (size--)
        {
            TreeNode* cur = q.front();
            q.pop();

            if (cur->left) q.push(cur->left);
            if (cur->right) q.push(cur->right);
        }
    }
    return depth;
}

2.递归

显然,深度等于 max(左子树深度,右子树深度) + 1

int maxDepth(TreeNode* root) {
    if (root == nullptr) return 0;

    return max(maxDepth(root->left), maxDepth(root->right)) + 1;
}

3.回溯法

回溯法我不怎么熟,所以还是写一遍。

这个方法就有点像是dfs的写法,其实我觉得代码随想录树的这一部分有点过于追求套路化,倒也不必非要去把问题都套路到前中后序遍历和层序遍历上去。

回溯法就是遍历所有可能性,在每个可能性中找到最符合要求的那个。回溯相比于递归,更像是一种暴力的搜索,把所有情况都检索一遍;而递归更像是把大问题拆解成**[子问题+常量级问题]**的格式

通常套路是这样:

typename 最终结果;

void 回溯函数(参数)
{
	修改最终结果
	
	if (可能性1)
	{
		维护目标++;
		回溯函数(维护目标);
		维护目标--;
	}
}

就是在你进入可能性时要修改那个参数,退出递归时要改回去。

举个例子,从根节点开始,高度为1,现在进入左子树,当前高度就会被修改到1+左子树高,等到你返回回来以后,高度又得改回1,然后再进入右子树,去计算1+右子树高度。

我们就以这道题目为例子

int res;	//最终结果
void getDepth(TreeNode* root, int depth)	//depth表示到该点目前的深度
{
    //如果depth超过res,那么更新res
    if (depth > res) res = depth;

    //如果已经没有子节点,直接返回
    if (root->left == nullptr && root->right == nullptr) return;

    //尝试加上左子树深度
    if (root->left)
    {
        depth++;
        getDepth(root->left, depth);
        depth--;
    }

    //尝试加上右子树深度
    if (root->right)
    {
        depth++;
        getDepth(root->right, depth);
        depth--;
    }
}

int maxDepth(TreeNode* root) {
    res = 0;
    if (root == nullptr) return 0;
    getDepth(root, 1);
    return res;
}

111.二叉树的最小深度 (优先掌握递归)

同昨天做过了,其实难点在于如果只有左子树或者只有右子树,那么不能把没有的一方当成高度0.

1.层序

int minDepth(TreeNode* root) {
    int depth = 0;
    queue<TreeNode*> q;

    if (root) q.push(root);
    while (!q.empty())
    {
        depth++;

        int size = q.size();
        while (size--)
        {
            TreeNode* cur = q.front();
            q.pop();

            if (cur->left) q.push(cur->left);
            if (cur->right) q.push(cur->right);

            if (cur->left == nullptr && cur->right == nullptr) 
            return depth;
        }
    }
    return depth;
}

2.递归

int minDepth(TreeNode* root) {
    if (root == nullptr) return 0;
    if (root->left == nullptr && root->right == nullptr) return 1;

    if (root->left == nullptr) return minDepth(root->right) + 1; 
    if (root->right == nullptr) return minDepth(root->left) + 1; 

    return min(minDepth(root->left), minDepth(root->right)) + 1;
}

3.回溯

int res;
void getDepth(TreeNode* root, int depth)
{
    if (root->left == nullptr && root->right == nullptr) 
    {
        res = res < depth ? res : depth;
    }

    if (root->left)
    {
        depth++;
        getDepth(root->left, depth);
        depth--;
    }

    if (root->right)
    {
        depth++;
        getDepth(root->right, depth);
        depth--;            
    }
}

int minDepth(TreeNode* root) {
    if (root == nullptr) return 0;
    res = INT_MAX;
    getDepth(root, 1);
    return res;
}

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

1.递归

明显,树结点数目 = 左子树结点数目 + 右子树节点数目 + 1

递归其实就是方程 + 终止条件,搞明白这两个就很简单(弄明白这两个自然你知道参数放什么)

int countNodes(TreeNode* root) {
    if (root == nullptr) return 0;

    return 1 + countNodes(root->left) + countNodes(root->right);
}

2.迭代

随便一种遍历方式,只要碰见新结点就加一,很容易。

我这里各写一个深度优先,层序也就是套模板,不写了(摆烂

int countNodes(TreeNode* root) {
    stack<TreeNode*> st;
    int res = 0;

    if (root) st.push(root);
    while (!st.empty())
    {
        TreeNode* cur = st.top();
        st.pop();

        if (cur != nullptr)
        {
            st.push(cur);
            st.push(nullptr);

            if (cur->left) st.push(cur->left);
            if (cur->right) st.push(cur->right);
        }
        else
        {
            st.pop();
            res++;
        }
    }
    return res;
}

3.完全二叉树的性质

其实如果知道是完全二叉树,完全可以根据树的性质

如果是一颗满二叉树,它的大小就是和高度h有关,为 2 h − 1 2^h -1 2h1

一棵向左遍历和向右遍历深度一样的完全二叉树一定是满二叉树,因此,我们借由这个性质,找到子树是满二叉树即可返回,大大缩减了递归深度。

只有一个点也是满二叉树

int countNodes(TreeNode* root) {
    if (root == nullptr) return 0;

    int left = 0, right = 0;
    TreeNode* cur = root;
    while (cur->left) {left++;cur = cur->left;}
    cur = root;
    while (cur->right) {right++;cur = cur->right;}

    if (left == right) return (2 << left) - 1;

    return countNodes(root->left) + countNodes(root->right) + 1;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

去人777

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值