思路:递归
- 首先要清除链表是如何展平的
- 之后需要注意,在我们展平子链表的时候,可能子链表还有child结点,对于这种问题,要联想到递归的解法
- 还有一点在于,需要考虑到可能一个链表有多个child需要展平,所以在书写递归函数时要把每个结点遍历一遍
- 最后是书写的细节,注意要仔细分析一下在子链表要插入进来时,每个涉及到的结点他们的一些属性是如何变化的
递归函数
class Solution {
//返回child链表的尾部结点
Node flattenGetTail(Node head) {
Node node = head, tail = null;
while (null != node) {
Node next = node.next;
if (null == node.child) {
tail = node;
} else {
Node childTail = flattenGetTail(node.child);
node.child.prev = node;
childTail.next = next;
node.next = node.child;
node.child = null;
if (null != next)
next.prev = childTail;
tail = childTail;
next = childTail;
}
node = next;
}
return tail;
}
public Node flatten(Node head) {
flattenGetTail(head);
return head;
}
}
非递归函数(用栈来模拟递归过程)
class Solution {
//判断有没有子链表
Node containsChild(Node head) {
while (null != head) {
if (null != head.child)
return head;
head = head.next;
}
return null;
}
//获取子链表的最后一个结点
Node getLastNode(Node head){
while(null != head.next)
head = head.next;
return head;
}
public Node flatten(Node head) {
if (null == head)
return null;
Stack<Node> nodeStack = new Stack<>();
Node father = containsChild(head);
if(null == father)
return head;
nodeStack.push(father);
while(!nodeStack.empty()){
father = containsChild(father.child);
if(null != father){
nodeStack.push(father);
}else{
father = nodeStack.pop();
Node fatherNext = father.next , lastNode = getLastNode(father.child);
father.next = father.child;
father.child.prev = father;
father.child = null;
lastNode.next = fatherNext;
if(null != fatherNext)
fatherNext.prev = lastNode;
}
}
return head;
}
}
可以发现,递归函数更加简洁而优雅
Go代码
func flatten(root *Node) *Node {
flatternRec(root)
return root
}
// 展平以root为根的双向链表并返回尾节点
func flatternRec(root *Node) *Node {
if root == nil {
return nil
}
var pre *Node
for node := root; node != nil; node = node.Next {
if node.Child != nil {
next := node.Next
node.Next = node.Child
node.Child.Prev = node
tail := flatternRec(node.Child)
node.Child = nil
tail.Next = next
if next != nil{
next.Prev = tail
}
node = tail
}
pre = node
}
return pre
}