问题

https://leetcode-cn.com/problems/reorder-list/

给定一个单链表 L:L0→L1→…→Ln-1→Ln , 将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

给定链表 1->2->3->4, 重新排列为 1->4->2->3.

示例 2:

给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.

思路

首先观察重排以后的链表,会发现是头尾交替连接的
那么我们可以当作是两个链表的交叉合并
image.png
给定链表 1->2->3->4, 重新排列为 1->4->2->3
要合并的这两个链表其中一个是链表的前半部分,另一个是链表后半部分的反转

这样我们就把问题转化成几个子问题:找到链表的中间节点,对后半部分的链表进行反转、合并两个链表

时间复杂度:O(n)
空间复杂度:O(1)

程序

  1. # Definition for singly-linked list.
  2. # class ListNode:
  3. # def __init__(self, val=0, next=None):
  4. # self.val = val
  5. # self.next = next
  6. class Solution:
  7. def reorderList(self, head: ListNode) -> None:
  8. """
  9. Do not return anything, modify head in-place instead.
  10. """
  11. dummy = ListNode(0)
  12. dummy.next = head
  13. # 找到中间节点
  14. low = dummy
  15. fast = dummy
  16. while fast and fast.next:
  17. low = low.next
  18. fast = fast.next.next
  19. mid = low.next
  20. low.next = None
  21. # 反转
  22. mid = self.reverse(mid)
  23. # 交叉合并两个链表
  24. self.merge_two_list(dummy.next, mid)
  25. # 反转链表
  26. def reverse(self, head: ListNode) -> ListNode:
  27. if not head:
  28. return None
  29. cur = None
  30. while head:
  31. node = head.next
  32. head.next = cur
  33. cur = head
  34. head = node
  35. return cur
  36. # 交叉合并两个链表
  37. def merge_two_list(self, l1: ListNode, l2: ListNode) -> ListNode:
  38. dummy = ListNode(0)
  39. cur = dummy
  40. while l1 and l2:
  41. # 先连 l1
  42. cur.next = l1
  43. cur = cur.next
  44. l1 = l1.next
  45. # 再连 l2
  46. cur.next = l2
  47. cur = cur.next
  48. l2 = l2.next
  49. # 对剩下的部分进行单独处理
  50. if l1:
  51. cur.next = l1
  52. if l2:
  53. cur.next = l2
  54. return dummy.next