合并两个有序链表

247 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

前言

笔者除了大学时期选修过《算法设计与分析》和《数据结构》还是浑浑噩噩度过的(当时觉得和编程没多大关系),其他时间对算法接触也比较少,但是随着开发时间变长对一些底层代码/处理机制有所接触越发觉得算法的重要性,所以决定开始系统的学习(主要是刷力扣上的题目)和整理,也希望还没开始学习的人尽早开始。

系列文章收录《算法》专栏中。

力扣题目链接

问题描述

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例 1:

image.png

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1 和 l2 均按 非递减顺序 排列

剖析

两个链表已经排好序了,可以使用双指针进行遍历比较大小,小的插在前面大的插在后面。步骤如下:

  1. 创建一个头节点 head,赋值返回结果的当前移动指针resultCurrent。
  2. 如果list1和list2都是非空的,当前指针((从头开始遍历))指向的元素进行比较,小的作为resultCurrent的next节点。
  3. 移动第2步较小链上的指针,resultCurrent=resultCurrent.next。重复第二步,直到list1或者list2遍历结束了。
  4. 其中一个遍历结束后把还没遍历结束的拼接在resultCurrent后面。

算法复杂度:

  • 时间复杂度:m和n分别为两个链表的长度,最差的情况是交叉进行,比如2->4->6和1->3->5。所以为O(m+n)。
  • 空间复杂度:O(1)。

代码

public static ListNode mergeTwoLists(ListNode list1, ListNode list2) {
    //创建一个头指针方便后面操作
    ListNode head = new ListNode(-1);
    //返回结果的链表当前位置
    ListNode resultCurrent = head;
    while (list1 != null && list2 != null) {
        //小于等于就拼接list1的节点,大于就拼接list2
        if (list1.val <= list2.val) {
            resultCurrent.next = list1;
            list1 = list1.next;
        } else {
            resultCurrent.next = list2;
            list2 = list2.next;
        }
        resultCurrent = resultCurrent.next;
    }

    //最后可能存在还没遍历完的链表,所以拼接上
    resultCurrent.next = list1 != null ? list1 : list2;
    return head.next;
}