#!/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()