Medium
题目描述
在一个无限二叉树中,每个节点都有两个子节点,节点按行顺序标记。
在奇数行(即第一、三、五行等),标记是从左到右的,而在偶数行(第二、四、六行等),标记是从右到左的。
给定树中一个节点的标签,返回从树根到带有该标签的节点的路径上的标签。
示例 1:
输入:label = 14
输出:[1,3,4,14]
示例 2:
输入:label = 26
输出:[1,2,6,10,26]
约束条件:
1 <= label <= 10^6
提示:
- 根据当前节点的标签,找出该节点父节点的标签必须是什么。
解题思路
这道题的关键是理解之字形标记的规律,并能够从子节点推导出父节点。
首先分析二叉树的标记规律:
- 第1层:1个节点,标记为1(从左到右)
- 第2层:2个节点,标记为3,2(从右到左)
- 第3层:4个节点,标记为4,5,6,7(从左到右)
- 第4层:8个节点,标记为15,14,13,12,11,10,9,8(从右到左)
解题思路:
- 确定节点层数:通过
log2(label)可以确定节点在第几层 - 找到父节点位置:在正常二叉树中,节点
label的父节点是label/2 - 处理之字形标记:由于偶数层是反向标记的,需要进行位置转换
- 从下往上构建路径:从给定节点开始,不断找父节点直到根节点
核心算法:
- 对于偶数层的节点,需要将其转换为对应的正常位置
- 转换公式:
正常位置 = 层的起始值 + 层的结束值 - 当前值 - 然后按正常二叉树规则找父节点,如果父节点在偶数层,再次转换
时间复杂度为O(log n),因为需要遍历从叶节点到根节点的路径。
代码实现
class Solution {
public:
vector<int> pathInZigZagTree(int label) {
vector<int> result;
while (label != 1) {
result.push_back(label);
// 找到当前层数
int level = log2(label) + 1;
// 如果当前层是偶数层(从右到左),需要转换为正常位置
if (level % 2 == 0) {
int levelStart = 1 << (level - 1);
int levelEnd = (1 << level) - 1;
label = levelStart + levelEnd - label;
}
// 找父节点
label = label / 2;
// 如果父节点在偶数层,需要转换为之字形位置
int parentLevel = level - 1;
if (parentLevel % 2 == 0) {
int levelStart = 1 << (parentLevel - 1);
int levelEnd = (1 << parentLevel) - 1;
label = levelStart + levelEnd - label;
}
}
result.push_back(1);
reverse(result.begin(), result.end());
return result;
}
};
class Solution:
def pathInZigZagTree(self, label: int) -> List[int]:
result = []
while label != 1:
result.append(label)
# 找到当前层数
level = label.bit_length()
# 如果当前层是偶数层(从右到左),需要转换为正常位置
if level % 2 == 0:
level_start = 1 << (level - 1)
level_end = (1 << level) - 1
label = level_start + level_end - label
# 找父节点
label = label // 2
# 如果父节点在偶数层,需要转换为之字形位置
parent_level = level - 1
if parent_level % 2 == 0:
level_start = 1 << (parent_level - 1)
level_end = (1 << parent_level) - 1
label = level_start + level_end - label
result.append(1)
return result[::-1]
public class Solution {
public IList<int> PathInZigZagTree(int label) {
List<int> result = new List<int>();
while (label != 1) {
result.Add(label);
// 找到当前层数
int level = (int)Math.Log2(label) + 1;
// 如果当前层是偶数层(从右到左),需要转换为正常位置
if (level % 2 == 0) {
int levelStart = 1 << (level - 1);
int levelEnd = (1 << level) - 1;
label = levelStart + levelEnd - label;
}
// 找父节点
label = label / 2;
// 如果父节点在偶数层,需要转换为之字形位置
int parentLevel = level - 1;
if (parentLevel % 2 == 0) {
int levelStart = 1 << (parentLevel - 1);
int levelEnd = (1 << parentLevel) - 1;
label = levelStart + levelEnd - label;
}
}
result.Add(1);
for (int i = 0; i < result.Count / 2; i++) {
int temp = result[i];
result[i] = result[result.Count - 1 - i];
result[result.Count - 1 - i] = temp;
}
return result;
}
}
var pathInZigZagTree = function(label) {
const path = [];
while (label >= 1) {
path.unshift(label);
// Find the level of current label
let level = Math.floor(Math.log2(label));
// Find the start and end of current level
let levelStart = Math.pow(2, level);
let levelEnd = Math.pow(2, level + 1) - 1;
// Convert to the position as if it were in normal binary tree
let normalPos;
if (level % 2 === 0) {
// Odd row (1-indexed), normal order
normalPos = label;
} else {
// Even row (1-indexed), reversed order
normalPos = levelStart + levelEnd - label;
}
// Find parent in normal binary tree
let parentNormal = Math.floor(normalPos / 2);
// Convert parent back to zigzag position
let parentLevel = level - 1;
if (parentLevel >= 0) {
let parentLevelStart = Math.pow(2, parentLevel);
let parentLevelEnd = Math.pow(2, parentLevel + 1) - 1;
if (parentLevel % 2 === 0) {
// Odd row, normal order
label = parentNormal;
} else {
// Even row, reversed order
label = parentLevelStart + parentLevelEnd - parentNormal;
}
} else {
break;
}
}
return path;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(log n) | 需要从给定节点遍历到根节点,路径长度为O(log n) |
| 空间复杂度 | O(log n) | 存储路径所需的额外空间 |