leetcode链表之重排链表
2022-03-28 本文已影响0人
小奚有话说
143、重排链表
题目:
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例1:
输入:head = [1,2,3,4]
输出:[1,4,2,3]
示例2:
输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]
思路:
这道题就是需要将链表首尾结点交替连接
解法1:
由于这是单向链表,所以没有前一个结点的指向,这个时候很自然的想到用数组,可以很方便的进行结点的选取
代码:
class Solution:
def reorderList(self, head: ListNode) -> None:
if not head: return
nodes = []
cur = head
# 遍历所有节点将,结点放入nodes里进行缓存
while cur:
nodes.append(nodes)
cur = cur.next
i, j = 0, len(nodes) - 1
# 头尾进行交替连接
while i < j:
nodes[i].next = nodes[j]
i += 1
# i+1之后如果和j相等,也就说明此时遍历已经完成,此时设置下一个结点为None,结束循环即可
if i == j:
nodes[i].next = None
break
nodes[j].next = nodes[i]
j -= 1
解法2:
在这道题之前,我们已经写过怎么查找链表的中点,反转链表,以及合并链表的操作。此时可以想到,如果从终点到尾结点进行反转,然后两个结点交替相接,也可以满足题目要求。
代码:
class Solution:
# 查询链表的中点,使用快慢指针
def getMedian(self, head):
slow = fast = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
return slow
# 反转链表,先将下一个指针缓存,然后将当前指针指向前一个指针,分别将当前指针和前一个指针向后移动即可
def reversed(self, head):
prev, cur = None, head
while cur:
next = cur.next
cur.next = prev
prev = cur
cur = next
return prev
# 合并两个链表,创建一个虚拟头结点,然后依次进行拼接,最后将未拼接完的拼接到链表后面即可
def merge(self, l1, l2):
cur = vHead = ListNode()
while l1 and l2:
cur.next = l1
l1 = l1.next
cur = cur.next
cur.next = l2
l2 = l2.next
cur = cur.next
cur.next = l1 or l2
return vHead.next
def reorderList(self, head: ListNode) -> None:
if not head: return
mid = self.getMedian(head)
# 这里注意使用中点的下一个结点,目的是为了将前面的结点从中部进行切断,
# 否则在合并的时候,头结点后面的也会进行合并,这样会导致拼接两次
midRevered = self.reversed(mid.next)
mid.next = None
self.merge(head, midRevered)