Python程序员面试算法宝典---解题总结: 第1章 链表 1.12 如何展开链接列表

#!/usr/bin/env python
# encoding: utf-8

'''
Python程序员面试算法宝典---解题总结: 第1章 链表 1.12 如何展开链接列表

题目:
给定一个有序链表,其中每个节点也表示一个有序链表,结点包含两个类型的指针:
(1) 指向主链表中下一个结点的指针(在下面的代码中称为正确指针)
(2) 指向此结点头的链表(在下面的代码中称为down指针)
所有链表都被排序。请参见以下示例:
3       ->      11      ->      15      ->      30
|V              |V              |V              |V
6               21              22              39
|V                              |V              |V
8                               50              40
|V                                              |V
31                                              55
实现一个函数flatten(),该函数用来将链表扁平化成单个链表,扁平化的链表也应该被排序。
例如,对于上述输入链表,输出链表应该为3->6->8->11->15->21->22->30->31->39->40->50->55

分析:
看上去就是一个排序的问题,从左上方的结点开始,每次应该只是与自己的右边结点和下边结点比较。
步骤1: 输出当前节点curr
步骤2:
2.1 如果自己下面结点< 右边结点,并让下面结点称为当前节点;
if curr.downNode and curr.newxtNode:

2.2 如果自己的右边结点 < 下面结点,让右边结点的下面结点成为右边结点,
并让右边结点成为当前节点
转步骤1,直到所有节点全部处理完成

不行,进行结点替换会导致顺序发生变化,需要用递归来做。
未能解出

关键:
1 用递归
用down指针来存储扁平化处理后的链表,
递归合并已经扁平化的链表与当前链表。
扁平化处理算法整体思路:
步骤1: 只要root为空,或者root的右节点为空,则返回root;
        否则进入步骤2
步骤2: 递归调用扁平化方法处理当前root右节点,并将处理后的结果
        赋值给当前节点的右节点;
步骤3: 将已经处理好的当前节点的右节点和当前节点进行链表合并

链表合并算法整体思路:
说明: 输入的参数是 当前节点和当前节点的右节点
需要用down指针保存扁平化后的结果
步骤1: 如果两个链表有一个为空,则返回另一个
步骤2: 将链表头结点较小的节点值赋给result,递归对
        链表头结点较大的链表和链表头结点较小的头结点的下一个节点做递归处理,
        处理后的结果作为复制给当前result的down指针


2 具体实现
    def mergeList2(self, a, b):
        if a == None:
            return b
        if b == None:
            return a
        # 把两个链表头中较小的节点赋值给result
        if a.data < b.data:
            result = a
            # 不懂,为什么这里设置的是 downNode而不是nextNode
            # 因为这里是用downNode指针存储扁平化后的链表,所以不是nextNode
            result.downNode = self.mergeList2(a.downNode, b)
        else:
            result = b
            result.downNode = self.mergeList2(a, b.downNode)
        return result

    def flatten(self, head):
        if not head or not head.nextNode:
            return head

        good:
        这里因为使用downNode存储扁平化后的指针,所以这里递归
        扁平化处理的处理时当前节点的右节点,
        递归处理head.nextNode链表
        比较的两个链表分别是用
        head和head.nextNode
       把head节点对应的链表与右边的链表合并
       递归遍历到结点15后的整体递归过程如下:
       (15, 30) -> result = 15, result.down=22
       (22, 30) -> result = 22, result.down=30
       (50, 30) -> result = 30, result.down=39
       (50, 39) -> result = 39, result.down=40
       (50, 40) -> result = 40, result.down=50
       (50, 55) -> result = 50, result.down=55
       (None,55)-> result = 55,
       最终对于节点15,得到了如下链表:
       15->22->30->39->40->50->55
       15节点被赋予给11节点的右节点
        head = self.mergeList2(head, head.nextNode)
        return head

参考:
Python程序员面试算法宝典
'''
class MergeList:
    def __init__(self):
        self.head = None

    def mergeList2(self, a, b):
        if a == None:
            return b
        if b == None:
            return a
        # 把两个链表头中较小的节点赋值给result
        if a.data < b.data:
            result = a
            # 不懂,为什么这里设置的是 downNode而不是nextNode
            # 因为这里是用downNode指针存储扁平化后的链表,所以不是nextNode
            result.downNode = self.mergeList2(a.downNode, b)
        else:
            result = b
            result.downNode = self.mergeList2(a, b.downNode)
        return result

    def flatten(self, head):
        if not head or not head.nextNode:
            return head

        '''
        good:
        这里因为使用downNode存储扁平化后的指针,所以这里递归
        扁平化处理的处理时当前节点的右节点,
        递归处理head.nextNode链表
        比较的两个链表分别是用
        head和head.nextNode
        '''
        head.nextNode = self.flatten(head.nextNode)
        '''
       把head节点对应的链表与右边的链表合并
       递归遍历到结点15后的整体递归过程如下:
       (15, 30) -> result = 15, result.down=22
       (22, 30) -> result = 22, result.down=30
       (50, 30) -> result = 30, result.down=39
       (50, 39) -> result = 39, result.down=40
       (50, 40) -> result = 40, result.down=50
       (50, 55) -> result = 50, result.down=55
       (None,55)-> result = 55,
       最终对于节点15,得到了如下链表:
       15->22->30->39->40->50->55
       15节点被赋予给11节点的右节点
       '''
        head = self.mergeList2(head, head.nextNode)
        return head

    def printList(self):
        curr = self.head
        result = ""
        while curr:
            if result:
                result += "->" + str(curr.data)
            else:
                result = str(curr.data)
            curr = curr.downNode
        print result


def costructList(arrList):
    if not arrList:
        return
    head = buildList(arrList[0])
    current = head
    for i,arr in enumerate(arrList):
        if 0 == i:
            continue
        newNode = buildList(arr)
        current.nextNode = newNode
        current = newNode
    return head


class Node(object):
    def __init__(self, data=None, nextNode=None, downNode=None):
        self.data = data
        self.nextNode = nextNode
        self.downNode = downNode


def buildList(arr):
    if not arr:
        return
    head = Node(arr[0])
    current = head
    for i, data in enumerate(arr):
        if 0 == i:
            continue
        newNode = Node(data)
        current.downNode = newNode
        current = newNode
    return head


def process():
    arr1 = [3, 6, 8, 31]
    arr2 = [11, 21]
    arr3 = [15, 22, 50]
    arr4 = [30, 39, 40, 55]
    arr = [arr1, arr2, arr3, arr4]
    head = costructList(arr)
    megList = MergeList()
    result = megList.flatten(head)
    megList.head = result
    megList.printList()


if __name__ == "__main__":
    process()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值