返回

Python 剖析 leetcode 86. Partition List:双指针巧妙分割链表

后端

导读

在计算机科学中,链表是一种常用的数据结构,它由一系列节点组成,每个节点包含一个数据项和指向下一个节点的指针。链表操作是编程中常见且重要的任务,其中分割链表是一种常见且实用的操作。在 leetcode 86. Partition List 这道题中,我们需要将链表分割成两个子链表,其中一个子链表包含所有小于或等于给定值的节点,另一个子链表包含所有大于给定值的节点。

解题思路

这道题目的关键在于如何高效地将链表分割成两个子链表。一种常用的方法是使用双指针法。双指针法是一种利用两个指针同时遍历链表的技巧,它可以帮助我们快速地找到特定位置的节点或执行分割操作。

具体来说,我们可以使用两个指针 prevcurr 来遍历链表。prev 指针始终指向当前节点的前一个节点,curr 指针指向当前节点。我们从链表的头节点开始遍历,如果 curr 指针指向的节点值小于或等于给定值,则将该节点移动到分割后的第一个子链表中,并将 prevcurr 指针都向前移动一个节点。如果 curr 指针指向的节点值大于给定值,则将该节点移动到分割后的第二个子链表中,并只将 curr 指针向前移动一个节点,因为 prev 指针需要留在当前节点上。

通过这种方式,我们可以在遍历链表的同时将链表分割成两个子链表。分割完成后,我们可以将分割后的两个子链表连接起来,形成最终的分割结果。

Python 代码实现

def partition(head, x):
    """
    Partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x.
    If x is contained within the list, the values of x only need to be after the elements less than x.
    The partition element x can appear anywhere in the "right partition"; it does not need to appear between the left and right partitions.
    :type head: ListNode
    :type x: int
    :rtype: ListNode
    """

    # Initialize two pointers, prev and curr, to traverse the list.
    prev = ListNode(0)
    prev.next = head
    curr = head

    # Move the prev and curr pointers until we find the first node with a value greater than or equal to x.
    while curr and curr.val < x:
        prev = prev.next
        curr = curr.next

    # If we have reached the end of the list, return the original list.
    if not curr:
        return head

    # Initialize two new lists, left_head and right_head, to store the partitioned lists.
    left_head = ListNode(0)
    right_head = ListNode(0)

    # Append nodes to the left and right lists based on their values.
    while curr:
        if curr.val < x:
            left_head.next = curr
            left_head = left_head.next
        else:
            right_head.next = curr
            right_head = right_head.next

        curr = curr.next

    # Connect the two lists and return the head of the partitioned list.
    left_head.next = right_head.next
    return prev.next

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的长度。我们只需要遍历链表一次,因此时间复杂度为 O(n)。
  • 空间复杂度:O(1),因为我们不需要额外的空间来存储数据。

结语

leetcode 86. Partition List 这道题目考察了双指针分割链表的基本操作。通过这道题,我们可以理解双指针法的原理和应用,并掌握链表分割的基本技巧。这种技巧在实际编程中非常有用,可以帮助我们解决各种各样的链表操作问题。