题目描述(难度:中等)
链表翻转是指把每 K 个相邻的结点看成一组进行翻转,如果剩余结点不足 K 个,则保持不变。假设给定链表 1->2->3->4->5->6->7 和一个数 K,如果 K 的值为 2,那么翻转后的链表为 2->1->4->3->6->5->7。如果 K 的值为 3,那么翻转后的链表为:3->2->1->6-> 5->4->7。(来源:腾讯)
单链表结构
class LNode:
def __init__(self):
self.data = None # 数据域
self.next = None # 指针域
- 由于单链表中每个结点的地址都存储在其前驱结点的指针域中,因此,对单链表中任何一个结点的访问只能从链表的头指针开始进行遍历。
- 注意:在修改结点指针域的时候,记录下后继结点的地址,否则会丢失后继结点。
方法一
以K=3为例,如下图所示。
# 对单链表翻转
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 != None:
next = cur.next
cur.next = pre
pre = cur
cur = next
return pre
# 对链表K翻转
def ReverseK(head, k):
if head == None or head.next == None or k < 2:
return
i = 1
pre = head
begin = head.next
end = None
pNext = None
while begin != None:
end = begin
# (1)找到从begin开始第K个结点,让end指向此结点
while i < k:
if end.next != None:
end = end.next
else: # 剩余结点的个数小于K
return
i += 1
pNext = end.next # (2)
end.next = None # (3)
pre.next = Reverse(begin) # (4)对begin单链表翻转
begin.next = pNext # (5)
pre = begin # (6)
begin = pNext # (7)
i = 1
复杂度分析
- 时间复杂度为 O ( n ) O(n) O(n),只对链表进行一次遍历。
- 空间复杂度为 O ( 1 ) O(1) O(1),只需常量个指针变量来保存结点的地址信息。
主函数
if __name__ == "__main__":
head = LNode()
head.next = None
cur = head
link = [1, 2, 3, 4, 5, 6, 7]
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
ReverseK(head, 3)
print("\n逆序输出:", end='')
cur = head.next
while cur != None:
print(cur.data, '', end='')
cur = cur.next
参考文献
[1] 何海涛. 剑指Offer:名企面试官精讲典型编程题(第2版). 北京: 电子工业出版社,2017
[2] 张波,楚秦. Python程序员面试算法宝典. 北京:机械工业出版社,2018