他选择了那个更温柔的她,而我,再也不用被他连接|力扣刷题第 21 题,我失恋了

98 阅读3分钟

1. 开始的开始|链表上的我们

李表义的感情生活,就像一条精心排序的链表——

有序、冷静、毫无波澜。

而我,黎婊啊,却是他生命中意料之外的闯入者,

像一段突如其来的代码,打破了他的完美序列。

她,是他青梅竹马的初恋。

温柔、乖巧、成绩优秀,不争不吵,仿佛天生就和他适配。

而我,锋利、果敢,情绪像指针一样跳跃,总是被贴上“不合适”的标签。

每次他面对我们两个,就像运行着一段无情的判断逻辑:

if (list1.val <= list2.val) {
    curNode.next = list1;
    list1 = list1.next;
} else {
    curNode.next = list2;
    list2 = list2.next;
}

她比我“更合适”一些,于是他朝她那边靠近;

她更“稳定”一点,于是他先牵起了她的手。

他不是偏心。只是太理性了。 他像是在执行代码,而我,却是运行结果里始终不被选择的那一项

我不甘心。拼命试图“变得更小”——

更听话,更温顺,只为了下一次能通过他的判断。

可终究,我不是她。

后来,她离开了。彻底离开了。

他站在原地,仿佛链表断了链接,整个人都失去了方向。

然后他终于想起了我。

他回头,试图把我重新接入他的人生:

curNode.next = list1 == null ? list2 : list1;

只是这一次,我已经不在原地等他了。

我走过了“判断语句”,穿过了自我否定,

走到了属于我自己的下一段人生。

我对他说:

“对不起,链表是单向的。你回不了头,而我也不会倒退。”

这段合并的链表终于结束了,

我从他的逻辑判断中退了出来,

不再是那个等着被“连接”的 list2。

他的人生继续向前,

而我,也终于不再等一个“值更小”的自己。

2. 题目链接

Q21. 合并两个有序链表 - 力扣(LeetCode)

3. 思路|合并的逻辑,也是一种放手

3.1 迭代法:双指针合并

核心逻辑: 两个链表都是非递减排序。 创建一个虚拟头节点 dummyHead,用一个指针 curNode 逐步拼接较小的节点。

题目的关键点:l1l2 均按 非递减顺序 排列

关键点

  • 比较 list1.vallist2.val
  • 将较小节点接到 curNode.next
  • 移动对应链表指针;
  • 最后把剩下的链表直接接上。

代码

public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
    ListNode dummyHead = new ListNode();
    ListNode curNode = dummyHead;
    while (list1 != null && list2 != null) {
        if (list1.val <= list2.val) {
            curNode.next = list1;
            list1 = list1.next;
        } else {
            curNode.next = list2;
            list2 = list2.next;
        }
        curNode = curNode.next;
    }
    curNode.next = list1 == null ? list2 : list1;
    return dummyHead.next;
}

3.2 递归法:将合并交给未来的自己

递归语义:合并两个链表,返回头节点 终止条件

  • 两个链表都为空,返回 null
  • 有一个为空,返回另一个。

递归拆解

  • 比较当前两个节点值;

  • 小的作为头节点,递归合并剩下的链表。

代码:

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

4. 总结

边界处理

  • 任一链表为 null 时,直接返回另一个;
  • 最终将未处理完的链表接到结果链表末尾;

技巧点

  • 哑节点(dummy head) 避免处理首节点特殊情况;

时间复杂度:O(n + m),其中 n 和 m 分别是两个链表的长度;

空间复杂度

  • 迭代法:O(1)

  • 递归法:O(n + m)(递归栈开销)

下次遇到类似题型,只要链表是有序的,优先想到用两个指针逐步比较并合并即可。