链表操作大全:LeetCode链表反转、环检测与合并模板

链表操作大全:LeetCode链表反转、环检测与合并模板

【免费下载链接】leetcode python 数据结构与算法 leetcode 算法题与书籍 刷算法全靠套路与总结!Crack LeetCode, not only how, but also why. 【免费下载链接】leetcode 项目地址: https://gitcode.com/gh_mirrors/leetcode82/leetcode

在数据结构与算法的学习中,链表是一种基础且重要的数据结构,广泛应用于各类算法题和实际工程中。本文将围绕LeetCode中常见的链表操作,详细介绍链表的反转、环检测与合并等核心模板,帮助新手快速掌握链表操作的精髓。

链表基础与核心结构

链表是由一系列节点组成的数据结构,每个节点包含数据域和指针域。在Python中,链表节点通常定义为:

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

链表的优势在于插入和删除操作的高效性,尤其是在链表头部或中间位置。但相比数组,链表的随机访问性能较差,需要从头节点开始遍历。

算法思维导图

算法思维导图:展示了链表在算法体系中的位置及相关知识点

一、链表反转:迭代与递归实现

链表反转是LeetCode中最经典的问题之一,主要有迭代和递归两种实现方式。

1. 迭代法反转链表

迭代法通过三个指针(prev、cur、next)的移动来实现链表的反转,时间复杂度O(n),空间复杂度O(1)。

def reverse_iteratively(head: ListNode) -> ListNode:
    prev, cur = None, head
    while cur:
        cur.next, cur, prev = prev, cur.next, cur
    return prev

核心思路

  • 初始化prev为None,cur为头节点
  • 遍历链表,每次将cur的next指向prev
  • 移动prev和cur指针,直到cur为None
  • prev即为反转后的头节点

2. 递归法反转链表

递归法通过将大问题分解为小问题来实现,代码简洁但理解难度稍高。

def reverse_recursively(head: ListNode) -> ListNode:
    def recursive(cur, pre=None):
        if not cur:
            return pre
        pre, cur.next = cur.next, pre
        return recursive(pre, cur)
    return recursive(head)

应用场景:LeetCode 206.反转链表、92.反转链表II等

二、环检测:Floyd判圈算法

判断链表中是否存在环以及找到环的入口,是链表操作中的另一个经典问题。Floyd判圈算法(快慢指针法)是解决此类问题的高效方法。

def detectCycle(head):
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow == fast:  # 存在环
            break
    else:  # 无环
        return None
    # 找环入口
    while head != slow:
        slow = slow.next
        head = head.next
    return head

算法原理

  1. 快指针每次走两步,慢指针每次走一步
  2. 若存在环,两指针必定相遇
  3. 相遇后,将慢指针移回头节点,两指针同速前进,再次相遇点即为环入口

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

三、链表合并:有序链表的合并

合并两个有序链表是链表操作中的常见需求,可通过迭代或递归实现。

1. 迭代法合并

def mergeTwoLists1(l1: ListNode, l2: ListNode) -> ListNode:
    curr = dummy = ListNode(0)
    while l1 and l2:
        if l1.val < l2.val:
            curr.next = l1
            l1 = l1.next
        else:
            curr.next = l2
            l2 = l2.next
        curr = curr.next
    curr.next = l1 or l2  # 处理剩余节点
    return dummy.next

2. 递归法合并

def mergeTwoLists2(a, b):
    if a and b:
        if a.val > b.val:
            a, b = b, a
        a.next = mergeTwoLists2(a.next, b)
    return a or b

应用场景:LeetCode 21.合并两个有序链表、23.合并K个升序链表

四、实战技巧与常见问题

1. 哑节点(Dummy Node)的使用

在头节点可能发生变化的场景(如合并、删除头节点),使用哑节点可以简化边界条件处理:

def dummy_node_assist(self, head):
    dummy = ListNode(0)
    cur = dummy.next = head
    # 处理逻辑...
    return dummy.next

2. K个一组翻转链表

LeetCode 25题要求每K个节点一组翻转链表,可结合迭代反转和哑节点实现:

def reverseKGroup1(head, k):
    dummy = jump = ListNode(0)
    dummy.next = l = r = head
    while True:
        count = 0
        while r and count < k:
            r = r.next
            count += 1
        if count == k:
            pre, cur = r, l
            for _ in range(k):
                cur.next, cur, pre = pre, cur.next, cur
            jump.next, jump, l = pre, l, r
        else:
            return dummy.next

3. 链表操作的时间复杂度分析

排序算法性能对比

排序算法性能对比图:链表相关操作的时间复杂度分析

常见链表操作的时间复杂度:

  • 访问节点:O(n)
  • 插入/删除节点:O(1)(已知前驱节点)
  • 反转链表:O(n)
  • 环检测:O(n)
  • 合并两个有序链表:O(m+n)

五、总结与资源推荐

链表操作是算法面试的基础,掌握本文介绍的反转、环检测和合并模板,能够解决大多数链表相关问题。更多实战案例和详细代码可参考:

通过大量练习,熟悉链表的指针操作和边界处理,能够显著提升解决复杂链表问题的能力。记住,刷算法全靠套路与总结,掌握这些模板将为你的算法之旅打下坚实基础!

【免费下载链接】leetcode python 数据结构与算法 leetcode 算法题与书籍 刷算法全靠套路与总结!Crack LeetCode, not only how, but also why. 【免费下载链接】leetcode 项目地址: https://gitcode.com/gh_mirrors/leetcode82/leetcode

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值