题目描述(难度:中等)
给定链表 L0->L1->L2…Ln-1->Ln,把链表重新排序为 L0->Ln->L1->Ln-1->L2-> Ln-2…。(来源:腾讯)
要求:
(1)在原来链表的基础上进行排序,即不能申请新的结点;
(2)只能修改结点的 next 域,不能修改数据域。
单链表结构
class LNode:
def __init__(self):
self.data = None # 数据域
self.next = None # 指针域
- 由于单链表中每个结点的地址都存储在其前驱结点的指针域中,因此,对单链表中任何一个结点的访问只能从链表的头指针开始进行遍历。
- 注意:在修改结点指针域的时候,记录下后继结点的地址,否则会丢失后继结点。
方法一
# 找出链表Head的中间结点,把链表从中间断成两个子链表
def FindMiddleNode(head):
if head is None or head.next is None:
return head
fast = head # 遍历链表的时候每次向前走两步
slow = head # 遍历链表的时候每次向前走一步
slowPre = head
# 当fast到链表尾时,slow恰好指向链表的中间结点
while fast is not None and fast.next is not None:
slowPre = slow
slow = slow.next
fast = fast.next.next
# 把链表断开成两个独立的子链表
slowPre.next = None
return slow
# 对不带头结点的单链表逆序
def Reverse(head):
if head == None or head.next == None:
return head
pre = head # 前驱结点
cur = head.next # 当前结点
next = cur.next # 后继结点
pre.next = None
# 使当前遍历到的结点cur指向其前驱结点
while cur is not None:
next = cur.next
cur.next = pre
pre = cur
cur = cur.next
cur = next
return pre
# 对链表进行排序
def Reorder(head):
if head == None or head.next == None or head.next.next == None:
return
# 前半部分链表第一个结点
cur1 = head.next
mid = FindMiddleNode(head.next)
# 后半部分链表逆序后的第一个结点
cur2 = Reverse(mid)
tmp = None
# 合并两个链表
while cur1.next is not None:
tmp = cur1.next
cur1.next = cur2
cur1 = tmp
tmp = cur2.next
cur2.next = cur1
cur2 = tmp
cur1.next = cur2
复杂度分析
- 时间复杂度为 O ( n ) O(n) O(n)
- 空间复杂度为 O ( 1 ) O(1) O(1)
主函数
if __name__ == "__main__":
head = LNode()
head.next = None
tmp = None
cur = head
# 构造第一个链表
link = [1, 2, 3, 4, 5]
for i in link:
tmp = LNode()
tmp.data = i
tmp.next = None
cur.next = tmp
cur = tmp
print("排序前:", end='')
cur = head.next
while cur != None:
print(cur.data, '', end='')
cur = cur.next
Reorder(head)
print("\n排序后:", end='')
cur = head.next
while cur != None:
print(cur.data, '', end='')
cur = cur.next
参考文献
[1] 何海涛. 剑指Offer:名企面试官精讲典型编程题(第2版). 北京: 电子工业出版社,2017
[2] 张波,楚秦. Python程序员面试算法宝典. 北京:机械工业出版社,2018