📜  给定一个已排序的链表,您将如何以排序方式插入(1)

📅  最后修改于: 2023-12-03 15:27:34.390000             🧑  作者: Mango

以排序方式插入已排序链表

假设我们已经有一个按照升序排列的链表,现在我们需要按照相同的方式插入一个新元素。这个问题具有一些简单的解法,但如果我们考虑插入效率和算法复杂度,那就需要花点时间研究。

解法
直接插入

最简单的解决方案是遍历链表,找到第一个大于等于当前元素的节点,然后将新元素插入到该节点之前。

def insert_sorted(head, val):
    new_node = ListNode(val)
    if val <= head.val:
        new_node.next = head
        return new_node
    curr = head
    while curr.next and curr.next.val < val:
        curr = curr.next
    new_node.next = curr.next
    curr.next = new_node
    return head

复杂度分析

  • 时间复杂度:O(n),其中n是链表中的元素个数。我们最坏的情况是遍历两遍链表,一次用于查找插入位置,一次用于插入新节点。
  • 空间复杂度:O(1),我们只需要常数空间来存储必要的节点指针。
二分查找

第二种解决方案利用链表已经按升序排列的特点,可以使用二分查找来找到元素插入位置。我们从链表的中间开始,尝试找到大于等于新元素的节点,然后继续在该节点左侧或右侧继续查找。

def insert_sorted(head, val):
    new_node = ListNode(val)
    if val <= head.val:
        new_node.next = head
        return new_node
    l, r = head, None
    while l:
        if l.val >= val:
            new_node.next = l
            r.next = new_node if r else new_node
            return head
        r, l = l, l.next
    r.next = new_node
    return head

复杂度分析

  • 时间复杂度:O(logn),其中n是链表中的元素个数。我们使用了二分查找来查找插入位置,而遍历链表的次数不超过O(logn)。
  • 空间复杂度:O(1),我们只需要常数空间来存储必要的节点指针。
双指针

第三种解决方案使用双指针,一个指针指向链表的头,另一个指针指向当前节点。我们遍历链表,找到第一个不小于新元素的节点,然后将新元素插入到该节点前面。

def insert_sorted(head, val):
    new_node = ListNode(val)
    dummy = ListNode(0, head)
    prev, curr = dummy, head
    while curr and curr.val < val:
        prev, curr = curr, curr.next
    prev.next, new_node.next = new_node, curr
    return dummy.next

复杂度分析

  • 时间复杂度:O(n),其中n是链表中的元素个数。我们最坏的情况是遍历两遍链表,一次用于查找插入位置,一次用于插入新节点。
  • 空间复杂度:O(1),我们只需要常数空间来存储必要的节点指针。
总结

以上三种解决方案都是可行的,它们的时间复杂度和空间复杂度也都不错。但双指针的解决方案最简洁,代码最短。所以,我们在面对这个问题时,可以优先考虑使用双指针算法。