返回

将两个有序链表巧妙融合:力扣经典题解,化繁为简

后端

引言

在计算机科学浩瀚的知识体系中,算法与数据结构犹如两颗璀璨的明珠,交相辉映,共同支撑着软件开发的稳健运行。其中,链表作为一种基本的数据结构,因其灵活性与高效性而被广泛应用于实际场景。合并两个有序链表,正是算法领域中一道颇具挑战性的经典题,考察着我们对链表操作的理解与掌握。

问题解析

给定两个升序有序链表head1head2,我们的目标是将其合并为一个新的升序链表,并返回该链表的头节点。需要注意的是,新链表需要由原有链表中的所有节点拼接而成。

解法一:递归

递归,是一种将问题分解为更小规模子问题的解决思路。针对本题,我们可以分别考虑两个链表的头部节点,将其中的较小者作为新链表的头部节点,然后递归合并余下的部分。

public ListNode mergeTwoLists(ListNode head1, ListNode head2) {
    if (head1 == null) {
        return head2;
    } else if (head2 == null) {
        return head1;
    } else if (head1.val < head2.val) {
        head1.next = mergeTwoLists(head1.next, head2);
        return head1;
    } else {
        head2.next = mergeTwoLists(head1, head2.next);
        return head2;
    }
}

解法二:迭代

迭代,是一种通过循环逐步逼近目标的解决思路。针对本题,我们可以使用两个指针cur1cur2分别指向head1head2,并创建一个新的空链表dummy作为合并后链表的虚拟头节点。然后,不断比较cur1cur2指向的节点的值,将较小者插入到dummy链表的尾部,并更新指针。

public ListNode mergeTwoLists(ListNode head1, ListNode head2) {
    ListNode dummy = new ListNode(0);
    ListNode cur = dummy;
    while (head1 != null && head2 != null) {
        if (head1.val < head2.val) {
            cur.next = head1;
            head1 = head1.next;
        } else {
            cur.next = head2;
            head2 = head2.next;
        }
        cur = cur.next;
    }
    if (head1 != null) {
        cur.next = head1;
    } else if (head2 != null) {
        cur.next = head2;
    }
    return dummy.next;
}

复杂度分析

  • 时间复杂度:对于递归解法,最坏情况下,链表的高度为n,合并操作需要递归调用n次,因此时间复杂度为O(n)。对于迭代解法,合并操作需要遍历两个链表,因此时间复杂度也为O(n)
  • 空间复杂度:对于递归解法,递归调用会消耗额外的栈空间,因此空间复杂度为O(n)。对于迭代解法,只需要额外的空间来存储新链表,因此空间复杂度为O(1)

总结

通过对递归和迭代两种方法的深入探讨,我们掌握了合并两个有序链表的本质,进一步提升了算法分析与解决问题的能力。力扣经典题的魅力就在于此,它不仅考察我们的编码技巧,更考验我们对算法思想的理解与灵活运用。

不断练习、不断思考,让我们在算法之旅中不断精进,成就更加强大的自我!