题目连接:LCR 028. 扁平化多级双向链表 - 力扣(LeetCode)
题目:
在一个多级双向链表中,节点除了有两个指针分别指向前后两个节点,还有一个指针指向它的子链表,并且子链表也是一个双向链表,它的节点也有指向子链表的指针。请将这样的多级双向链表展平成普通的双向链表,即所有节点都没有子链表。例如,下图 (a) 所示是一个多级双向链表,它展平之后如下图 (b) 所示。
节点的定义:
class Node {
public:
int val;
Node* prev;
Node* next;
Node* child;
};
分析:
在面试时如果遇到这种类型的题目,应聘者需要先弄清楚展平的规则。在上图的示例中,节点 2 有一个子链表,展平之后该子链表插入节点 2 和它的下一个节点 3 之间。节点 6 也有一个子链表,展平之后该子链表插入节点 6 和它的下一个节点 7 之间。由此可知,展平的规则是一个节点的子链展平之后将插入该节点和它的下一个节点之间。
由于子链表中的节点也可能有子链表,因此这里的链表是一个递归的结构。在展平子链表时,如果它也有自己的子链表,那么它嵌套的子链表也要一起展平。嵌套子链表和外层子链表的结构类似,可以用同样的方法展平,因此可以用递归函数来展平链表。
代码实现:
class Solution {
public:
Node* flattenAndGetTail(Node* head) {
Node* cur = head;
Node* tail = nullptr;
while (cur)
{
Node* next = cur->next;
if (cur->child)
{
Node* child = cur->child;
Node* childTail = flattenAndGetTail(child);
cur->child = nullptr;
cur->next = child;
child->prev = cur;
childTail->next = next;
if (next)
next->prev = childTail;
tail = childTail;
}
else
{
tail = cur;
}
cur = next;
}
return tail;
}
Node* flatten(Node* head) {
flattenAndGetTail(head);
return head;
}
};
在上述代码中,递归函数 flattenAndGetTail 在展平以 head 为头节点的链表之后返回链表的尾节点。在该函数中需要逐一扫描链表中的节点。如果一个节点 cur 有子链表,由于子链表也可能有嵌套的子链表,因此先递归调用 flattenAndGetTail 函数展平子链表,子链表展平之后的头节点是 child,尾节点是 childTail。最后将展平的子链表插入节点 node 和它的下一个节点 next 之间,即把展平的子链表的头节点 child 插入节点 cur 之后,并将尾节点 childTail 插入节点 next 之前。