143. 重排链表

题目

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, 5 * 10^4]
  • 1 <= node.val <= 1000

解题

方法一:

思路
  1. 使用快慢指针找到链表的中间节点,并将链表分为两部分。
  2. 将后半部分链表反转。
  3. 依次将后半部分的节点插入到前半部分链表中,实现重新排列。
代码
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reorderList(self, head: Optional[ListNode]) -> None:
        if not head or not head.next:
            return head

        # Step 1: 快慢指针找到链表的中间节点
        slow = fast = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next


        # 分割链表
        l1 = head
        l2 = slow.next
        slow.next = None
        # 一个问题是两半的时候怎么取? 中间那个在前在后都一样。

        # Step 2: 前插反转后半部分链表
        pre = None
        curr = l2
        while curr:
            next_node = curr.next
            curr.next = pre
            pre = curr
            curr = next_node
        l2 = pre

        # 注意:链表的更新,以及判断链表是否为空
        # Step 3: 后插重新排列链表
        # 注意:插入的时候,最后一次循环对链表的结尾是什么影响
        while l2:
            next_l1 = l1.next
            next_l2 = l2.next
            l1.next = l2
            l2.next = next_l1
            l1 = next_l1
            l2 = next_l2
  1. 首先,在定义 Solution 类时,reorderList 方法接收一个名为 head 的可选的 ListNode 参数,并且不返回任何值。
  2. 在方法内部,使用条件判断 if not head or not head.next: 来检查链表是否为空或只有一个节点,如果是,则直接返回该链表。
  3. 接下来,定义两个指针 slowfast,并将它们都指向链表的头节点 head。这里使用快慢指针的方式来找到链表的中间节点。
  4. 进行循环遍历,条件为 while fast and fast.next: 表示只要 fastfast.next 都不为空,就执行循环体内的代码。在每次迭代中,将 slow 指针向后移动一步,将 fast 指针向后移动两步,以实现快慢指针的效果。
  5. 当循环结束后,快指针 fast 要么已经到达链表末尾(偶数个节点),要么已经到达倒数第二个节点(奇数个节点)。
  6. 然后,我们需要分割链表。将 l1 设置为链表的头节点 head,将 l2 设置为慢指针 slow 的下一个节点 slow.next,然后将 slow.next 置为 None,即断开链表连接。
  7. 接下来,我们需要反转后半部分链表。定义一个前置节点 pre 并初始化为 None,定义一个当前节点 curr 并初始化为 l2,然后进行迭代。
    • 在每次迭代中,首先获取当前节点 curr 的下一个节点 next_node
    • 然后将当前节点的 next 指针指向前置节点 pre,实现反转。
    • 接着,将前置节点 pre 更新为当前节点 curr,将当前节点 curr 更新为下一个节点 next_node
    • 重复上述步骤,直到当前节点 currNone,即反转后半部分链表完成。
  8. 最后,我们需要重新排列链表。使用循环遍历 l1l2,条件为 while l1 and l2 表示只要 l1l2 都不为空,就执行循环体内的代码。
    • 在每次迭代中,首先分别保存 l1l2 的下一个节点,即 next_l1 = l1.nextnext_l2 = l2.next
    • 然后,将 l2 插入到 l1 的后面,即将 l1.next 指向 l2
    • 再将 l2.next 指向 next_l1,以将 l2 连接到 l1 后面。
    • 最后,更新 l1 为下一个节点 next_l1,更新 l2 为下一个节点 next_l2
    • 重复上述步骤,直到 l1l2None,即重新排列链表完成。

扩展
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值