同一算法不同解法(合并两个有序链表)

174 阅读3分钟

6. 合并两个有序链表

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

merge_ex1.jpg

示例 1:

输入: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
  • l1l2 均按 非递减顺序 排列

在做这个题目的时候先了解一下数据结构--链表

单链表

概念介绍

链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。以“结点的序列”表示线性表称作线性链表(单链表),单链表是链式存取的结构。

链接存储方法

链接方式存储的线性表简称为链表(Linked List)。

链表的具体存储表示为:

① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)

② 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))

链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示各种非线性的数据结构。

结点结构

┌───┬───┐

│data │next │

└───┴───┘

data域--存放结点值的数据域

next域--存放结点的直接后继的地址(位置)的指针域(链域)

链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的,每个结点只有一个链域的链表称为单链表(Single Linked List)。

头指针head和终端结点

单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。链表由头指针唯一确定,单链表可以用头指针的名字来命名。终端结点无后继,故终端结点的指针域为空,即NULL。

了解以上基本知识之后实现上面题目的代码如下:

var mergeTwoLists = function(list1, 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;
    }
}
思路: 两个链表的当前的节点的值相互比较,保留较小的,再将较小的节点的下一个节点A和另一个链表的当前
节点B比较,如果A小于B,list1.next 还是指向 list1 否则指向list2。重复以上的操作直至其中有一个链表为空。
根据代码显而易见重复以操作采用的是递归

image-20221006161803999.png

遇到这个问题总是第一反应使用递归,但是做完之后又感觉递归不完美,就非常解决,如果你也有这种感受 可以看下下面的思路

var mergeTwoLists = function(list1, list2) {
    const preHead = new ListNode(-1)
    let pre = preHead
    while(list1 && list2){
        if(list1.val <= list2.val){
            pre.next = list1
            list1 = list1.next
        }else{
            pre.next = list2
            list2 = list2.next
        }
        pre = pre.next
    }
    pre.next = list1 === null ? list2 : list1
    return preHead.next
};

image-20221006162745005.png

思路: 建立了一个空链表preHead 并且同时创建了一个头指针pre 指向创建的空链表
使用while 代替递归循环比较两个链表的当前节点,那个小就将pre.next指向谁,相当于向preHead链表中添加节点。