牛客国庆集训派对Day2 F、平衡二叉树 【构造+记忆化搜索】

探讨了在特定高度和平衡条件下,平衡二叉树的不平衡度计算问题,通过构造和记忆化搜索优化,找到所有高度为n的平衡树中不平衡度的最大值。

任意门:https://www.nowcoder.com/acm/contest/202/F

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 1048576K,其他语言2097152K
64bit IO Format: %lld

题目描述 

平衡二叉树,顾名思义就是一棵“平衡”的二叉树。在这道题中,“平衡”的定义为,对于树中任意一个节点,都满足左右子树的高度差不超过 d. 空树的高度定义为0,单个节点的高度为1,其他情况下树的高度定义为根节点左右子树高度最大值 + 1. 一棵在高度上平衡的树,节点数可能不平衡,因此再定义一棵树的不平衡度为这棵树中所有节点的左右子树的节点数之差的最大值。
给定平衡的定义参数d, 你需要求出所有高度为 n 的平衡树中不平衡度的最大值。

输入描述:

两个整数,n, d.

输出描述:

一个整数:所有高度为 n 的平衡树中不平衡度的最大值。
示例1

输入

复制
4 1

输出

复制
5

说明

下面这棵树在 d=1 的定义下高度是平衡的,其不平衡度为 5。
 

备注:

0 ≤ n, d ≤ 60

 

 

题意概括:

不要被题目蒙骗了,这是一道找规律和构造的题目。

tip:注意是所有左右子树的高度差为 d,不平衡度也是所有左右子树比较后的最大的那个。

解题思路:

思路很清晰嘛,第一个左结点为根的子树为满二叉树,第一个右结点的子树以尽量少的结点数构成一颗满足条件的二叉树,答案为这两颗子树的结点之差。

第一个左子树为满二叉树,左子树结点数 2^(N-1)-1; (快速幂)

那右边的那一半呢就进行构造建树吧,具体实现为 dfs ,每次构造它的左子树和右子树,直到达到需要的高度。但是一开始纯dfs是肯定超时,这时候需要记忆化搜索优化一下。

 

AC code:

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstring>
 5 #define LL long long
 6 using namespace std;
 7 LL dp[100][100];
 8 int N,d;
 9 
10 LL dfs(int h, int step)
11 {
12     if(dp[h][step] != -1) return dp[h][step];
13     LL sum = 1LL;
14     if(step == h) {dp[h][step] = sum; return sum;}
15     sum += dfs(h, step+1);                  //左子树
16     if(step >= h-d) {dp[h][step] = sum; return sum;}
17     sum += dfs(h-d, step+1);  //右子树
18     dp[h][step] = sum;
19     return sum;
20 }
21 
22 LL qpow(int x, int n)
23 {
24     LL ans = 1, base = x;
25     while(n != 0){
26         if(n&1!=0) ans*=base;
27         base*=base;
28         n>>=1;
29     }
30     return ans;
31 }
32 
33 int main()
34 {
35     //d = 1;
36     //printf("%d\n", dfs(3, 1));
37     LL L, R;
38     //while(~scanf("%lld%lld", &N, &d)){
39     scanf("%d%d", &N, &d);
40     memset(dp, -1, sizeof(dp));
41     if(N == 0 || d == 0) L = 0, R = 0;
42     else{
43         L = qpow(2, N-1)-1;
44         if(d >= N-1 ) R = 0;
45         else  R = dfs(N-d, 2);
46     }
47     //printf("L:%lld R:%lld\n", L, R);
48     printf("%lld\n", L-R);
49     //}
50     return 0;
51 }
View Code

 

### 牛客 BM2 的 C++ 实现 BM2 是一道经典的算法题目,主要涉及二叉树的最大路径和问题。以下是基于已知信息以及常见解决思路给出的 C++ 实现。 #### 方法概述 该问题可以通过 **动态规划** 和 **递归回溯** 来求解。核心思想是从根节点出发,计算经过任意节点的最大路径和。对于每一个节点,其贡献可以分为两种情况: 1. 节点作为路径的一部分(单边向下延伸)。 2. 节点成为路径的转折点(左子树 + 右子树 + 当前节点值)。 最终通过递归的方式自底向上更新全局最大值。 --- #### C++ 实现代码 ```cpp /** * Definition for a binary tree node. */ struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; class Solution { public: int maxPathSum(TreeNode* root) { if (!root) return INT_MIN; // 边界条件处理 int globalMax = INT_MIN; helper(root, globalMax); return globalMax; } private: int helper(TreeNode* node, int& globalMax) { if (!node) return 0; // 左右子树的最大贡献值,忽略负数部分 int leftGain = std::max(helper(node->left, globalMax), 0); int rightGain = std::max(helper(node->right, globalMax), 0); // 更新当前节点为路径转折点时的最大值 int currentMax = node->val + leftGain + rightGain; globalMax = std::max(globalMax, currentMax); // 返回以当前节点为起点的一侧最大路径和 return node->val + std::max(leftGain, rightGain); } }; ``` --- #### 关键点解析 1. **递归函数设计** - `helper` 函数用于计算以某个节点为根的最大路径和,并将其结果存储到 `globalMax` 中。 - 对于每个节点,分别考虑左侧和右侧子树的最大贡献值[^3]。 2. **边界条件** - 如果当前节点为空,则返回 0 表示无贡献。 - 使用 `INT_MIN` 初始化全局变量 `globalMax`,确保能够正确记录最小可能值。 3. **优化细节** - 避免重复计算子树的最大路径和,利用递归特性一次完成所有节点的访问。 --- #### 时间与空间复杂分析 - **时间复杂**: O(n),其中 n 是二叉树中节点的数量。每个节点仅被访问一次。 - **空间复杂**: O(h),h 是二叉树的高度。最坏情况下(退化成链表),空间复杂为 O(n)[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值