剑指offer 专项突破版 28、展平多级双向链表

题目链接

思路:递归
  • 首先要清除链表是如何展平的
  • 之后需要注意,在我们展平子链表的时候,可能子链表还有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
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值