面试经典算法25 - 二叉树展开为链表
LeetCode.114
公众号:阿Q技术站
问题描述
给你二叉树的根结点 root
,请你将它展开为一个单链表:
- 展开后的单链表应该同样使用
TreeNode
,其中right
子指针指向链表中下一个结点,而左子指针始终为null
。 - 展开后的单链表应该与二叉树先序遍历顺序相同。
示例 1:
输入:root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [0]
输出:[0]
提示:
- 树中结点数在范围
[0, 2000]
内 -100 <= Node.val <= 100
思路
递归
- 对于每个节点,如果其左子节点不为空,则将其左子节点和右子节点分别展开成单链表。
- 将左子节点展开后的单链表接到根节点的右子节点位置。
- 将右子节点展开后的单链表接到左子节点展开后的单链表的最后一个节点的右子节点位置。
非递归
- 将左子树插入到右子树的地方。
- 将原来的右子树接到左子树的最右边节点。
- 考虑新的右子树的根节点,重复上述步骤,直到所有节点都被展开。
具体步骤如下:
- 对于当前节点
node
,如果其左子节点不为空,则将其左子节点插入到右子节点的位置,然后将左子节点设为nullptr
。 - 将原来的右子节点接到当前右子节点的最右边节点的右子节点。
- 将当前节点移动到其右子节点,重复步骤1和2,直到当前节点为空。
图解
- 从根节点root开始,遍历二叉树的每个节点curr。
- 如果当前节点
curr
的左节点不为空,找到左子树的最右边节点leftRightMost
。
- 将当前节点
curr
的右子节点接到leftRightMost
的右子节点。
- 将当前节点
curr
的左子节点插入到当前节点curr
的右子节点位置,将当前节点curr
的左子节点置空。
- 将当前节点
curr
移动到其右子节点。
- 将当前节点
curr
的左子节点插入到当前节点curr
的右子节点位置,将当前节点curr
的左子节点置空。
- 将原来的右子树接到左子树的最右边节点
参考代码
C++
递归
#include <iostream>
using namespace std;
// 二叉树节点的定义
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
void flatten(TreeNode* root) {
if (!root) return;
flatten(root->left); // 展开左子树
flatten(root->right); // 展开右子树
TreeNode* left = root->left;
TreeNode* right = root->right;
root->left = nullptr;
root->right = left;
TreeNode* curr = root;
while (curr->right) {
curr = curr->right;
}
curr->right = right;
}
// 打印展开后的链表
void printList(TreeNode* root) {
while (root) {
cout << root->val << " ";
root = root->right;
}
cout << endl;
}
// 创建二叉树
TreeNode* createTree(vector<int>& nodes, int index) {
if (index >= nodes.size() || nodes[index] == -1) {
return nullptr; // 如果节点为空,则返回nullptr
}
TreeNode* root = new TreeNode(nodes[index]); // 创建当前节点
root->left = createTree(nodes, 2 * index + 1); // 创建左子树
root->right = createTree(nodes, 2 * index + 2); // 创建右子树
return root; // 返回当前节点
}
int main() {
vector<int> nodes = {1, 2, 5, 3, 4, -1, 6}; // 二叉树的先序遍历序列
TreeNode* root = createTree(nodes, 0); // 创建二叉树
flatten(root); // 展开为单链表
printList(root); // 打印展开后的链表
return 0;
}
非递归
#include <iostream>
using namespace std;
// 二叉树节点的定义
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
void flatten(TreeNode* root) {
TreeNode* curr = root;
while (curr) {
if (curr->left) {
// 找到左子树的最右边节点
TreeNode* leftRightMost = curr->left;
while (leftRightMost->right) {
leftRightMost = leftRightMost->right;
}
// 将原右子树接到左子树最右边节点的右子节点
leftRightMost->right = curr->right;
// 将左子树插入到右子树的位置
curr->right = curr->left;
curr->left = nullptr;
}
// 移动到下一个节点
curr = curr->right;
}
}
// 打印展开后的链表
void printList(TreeNode* root) {
while (root) {
cout << root->val << " ";
root = root->right;
}
cout << endl;
}
// 创建二叉树
TreeNode* createTree(vector<int>& nodes, int index) {
if (index >= nodes.size() || nodes[index] == -1) {
return nullptr; // 如果节点为空,则返回nullptr
}
TreeNode* root = new TreeNode(nodes[index]); // 创建当前节点
root->left = createTree(nodes, 2 * index + 1); // 创建左子树
root->right = createTree(nodes, 2 * index + 2); // 创建右子树
return root; // 返回当前节点
}
int main() {
vector<int> nodes = {1, 2, 5, 3, 4, -1, 6}; // 二叉树的先序遍历序列
TreeNode* root = createTree(nodes, 0); // 创建二叉树
flatten(root); // 展开为单链表
printList(root); // 打印展开后的链表
return 0;
}
Java
// 二叉树节点的定义
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
class Solution {
public void flatten(TreeNode root) {
TreeNode curr = root;
while (curr != null) {
if (curr.left != null) {
// 找到左子树的最右边节点
TreeNode leftRightMost = curr.left;
while (leftRightMost.right != null) {
leftRightMost = leftRightMost.right;
}
// 将原右子树接到左子树最右边节点的右子节点
leftRightMost.right = curr.right;
// 将左子树插入到右子树的位置
curr.right = curr.left;
curr.left = null;
}
// 移动到下一个节点
curr = curr.right;
}
}
// 测试函数
public static void main(String[] args) {
Solution solution = new Solution();
// 创建二叉树
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(5);
root.left.left = new TreeNode(3);
root.left.right = new TreeNode(4);
root.right.right = new TreeNode(6);
// 展开为单链表
solution.flatten(root);
// 打印展开后的链表
TreeNode curr = root;
while (curr != null) {
System.out.print(curr.val + " ");
curr = curr.right;
}
System.out.println();
}
}
Python
# 二叉树节点的定义
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def flatten(self, root: TreeNode) -> None:
curr = root
while curr:
if curr.left:
# 找到左子树的最右边节点
left_rightmost = curr.left
while left_rightmost.right:
left_rightmost = left_rightmost.right
# 将原右子树接到左子树最右边节点的右子节点
left_rightmost.right = curr.right
# 将左子树插入到右子树的位置
curr.right = curr.left
curr.left = None
# 移动到下一个节点
curr = curr.right
# 创建二叉树
def create_tree(nodes, index):
if index >= len(nodes) or nodes[index] == -1:
return None
root = TreeNode(nodes[index])
root.left = create_tree(nodes, 2 * index + 1)
root.right = create_tree(nodes, 2 * index + 2)
return root
# 打印展开后的链表
def print_list(root):
while root:
print(root.val, end=' ')
root = root.right
print()
# 测试代码
nodes = [1, 2, 5, 3, 4, -1, 6]
root = create_tree(nodes, 0)
solution = Solution()
solution.flatten(root)
print_list(root)