华为OD机试(C卷+D卷)2024真题目录(Java & c++ & python)
题目描述
给定长度为 n 的无序的数字数组,每个数字代表二叉树的叶子节点的权值,数字数组的值均大于等于1。
请完成一个函数,根据输入的数字数组,生成哈夫曼树,并将哈夫曼树按照中序遍历输出。
为了保证输出的二叉树中序遍历结果统一,增加以下限制:
二叉树节点中,左节点权值小于右节点权值,根节点权值为左右节点权值之和。当左右节点权值相同时,左子树高度小于等于右子树高度。
注意:
所有用例保证有效,并能生成哈夫曼树。
提醒:
哈夫曼树又称为最优二叉树,是一种带权路径长度最短的二叉树。
所谓树的带权路径长度,就是树中所有的叶节点的权值乘上其到根节点的路径长度(若根节点为 0 层,叶节点到根节点的路径长度为叶节点的层数)
输入描述
例如:由叶子节点:5 15 40 30 10,生成的最优二叉树如下图所示,该树的最短带权路径长度为:40 * 1 + 30 * 2 + 15 * 3 + 5 * 4 + 10 * 4 = 205。
输出描述
输出一个哈夫曼的中序遍历数组,数值间以空格分隔
示例1
输入
5
5 15 40 30 10
输出
40 100 30 60 15 30 5 15 10
说明:根据输入,生成哈夫曼树,按照中序遍历返回。所有节点中,左节点权值小于等于右节点权值之和。当左右节点权值相同时,左子树高度小于右子树。结果如上图所示。
解题思路
构建哈夫曼树。
哈夫曼树定义:
给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。
构建方法:
- 取出两个最小的权值
- 放回两个最小权值的合并和
- 直至剩一个元素
可以发现涉及最小值的存取,那么用优先队列来提速。
题目的特定限制:
二叉树节点中,左节点权值小于右节点权值,根节点权值为左右节点权值之和。当左右节点权值相同时,左子树高度小于等于右子树高度。
这是为了保证输出的二叉树中序遍历结果统一
参考代码
import heapq
class Node:
def __init__(self, lc, rc, weight, height):
self.lc = lc # 左孩子节点
self.rc = rc # 右孩子节点
self.weight = weight # 当前节点的权重
self.height = height # 当前节点代表子树的高度
def __lt__(self, other):
# 优先级比较时,权重小的优先级更高,权重相同时,高度小的优先级更高
if self.weight != other.weight:
return self.weight < other.weight
else:
return self.height < other.height
# 输入获取
n = int(input())
weights = list(map(int, input().split()))
# 二叉树中序遍历
def inOrder(root, seq):
if root.lc is not None:
inOrder(root.lc, seq)
seq.append(root.weight)
if root.rc is not None:
inOrder(root.rc, seq)
pq = []
# 创建n个哈夫曼树节点,并加入优先队列
for w in weights:
heapq.heappush(pq, Node(None, None, w, 0))
# 初始n个节点经过多轮合并,只剩一个节点时,那么该节点就是哈夫曼树的根节点,因此当优先队列中只剩一个节点时即可停止合并
while len(pq) > 1:
lc = heapq.heappop(pq)
rc = heapq.heappop(pq)
# 将lc和rc合并,合并后新节点fa的权重,是两个子节点权重之和,fa子树高度为最大高度+1
fa_weight = lc.weight + rc.weight
fa_height = max(lc.height, rc.height) + 1
# 将合并后的新节点加入优先队列
heapq.heappush(pq, Node(lc, rc, fa_weight, fa_height))
# 最后优先队列中必然只剩一个节点,即哈夫曼树的根节点,此时对此根节点(哈夫曼树)进行中序遍历
root = heapq.heappop(pq)
seq = []
inOrder(root, seq)
print(" ".join(map(str, seq)))