【Leetcode】Merge Two Sorted Lists题解

149 阅读1分钟

这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战

题目

将两个有序链表合并成一个有序链表,即按照递增顺序的有序链表

Merge two sorted linked lists and return it as a sorted list. The list should be made by splicing together the nodes of the first two lists.

示例如下:

Input: l1 = [1,2,4], l2 = [1,3,4]
Output: [1,1,2,3,4,4]

Input: l1 = [], l2 = [0]
Output: [0]

技术点

采用typescript来解决该题,为此在github上建了一个仓库,部分代码和思路见下文:

新建mergeTwoLists方法,该方法接收两个数组链表,注意,再将两个数组传入时,我们需先将数组转化为有序链表

import { ListNode } from '../../structures/ListNode'

// 方法一
export function mergeTwoLists(l1: ListNode | null, l2: ListNode | null): ListNode |null {
    const head: ListNode = new ListNode(); // 创建空头部节点
    let curr: ListNode = head; // curr节点指向head的引用地址
    while (l1 && l2) {
        if (l1.val < l2.val) {
            curr.next = l1;
            l1 = l1.next;
        } else {
            curr.next = l2;
            l2 = l2.next;
        }
        curr = curr.next;
    }
    curr.next = l1 || l2; // 因while循环已结束,这意味着l1或l2节点可能有值,此时取剩下的值即可
    return head.next;// 返回头部节点的next值,即指向整个有序的合并链表
}

比如l1链表对应的数组为[1,2]l2链表对应的数组为[3,4],在该方法开始前创建一个空节点head,指针curr指向head的引用地址,当l1l2链表皆有值时,比较两个链表的值

第一次比较,1 < 3,此时currnextListNode { val: 1, next: ListNode { val: 2, next: null } }l1链表指针往后移动

第二次比较,2 < 3,此时currnextListNode { val: 2, next: null }l1链表指针往后移动,指向null

第三次比较,由于l1已为null,跳出while循环,currnext指向l2整个有序链表ListNode { val: 3, next: ListNode { val: 4, next: null } }

最后,返回节点headnext值,该值为ListNode { val: 1, next: ListNode { val: 2, next: ListNode { val: 3, next: [ListNode] } } }

headcurr的比喻关系

在一个房间内,head呆坐在某个地方,此时curr来了,对head说:“你不用动,外面有2个大容器(对应上面例子数组[1,2], [3,4]),每个大容器里面分别有两个小箱子,我将这些小箱子按照从小到大的顺序都搬进来”。于是curr开始忙起来了,跑出去搬来最小的箱子放在head面前,紧接着继续将稍大一些的箱子放在之前箱子的后面。当A容器内的箱子全部搬完后,curr累的坐在B容器中最小的箱子上,curr的位置是多变的,而head的面前始终是这一排已经排好序的箱子。所以,在函数的最后,返回的是head.next,便是这个道理。

ListNode类

该类构建一个Node节点,代码如下所示:

export class ListNode {
    val?: number
    next?: ListNode | null
    constructor(val?: number, next?: ListNode | null) {
        this.val = (val === undefined ? 0 : val)
        this.next = (next === undefined ? null : next)
    }
}

如何测试

在测试时,我们需先将传入的数组转变为Node链表,再将结果链表转变成数组,与期望的数组进行对比即可。

数组转变成链表方法如下所示:

export function IntsToList(nums:Array<number|null>):ListNode | null {
    if (nums.length === 0) return null
    let l = new ListNode()
    let t = l
    nums.forEach(v => {
        t.next = new ListNode(v)
        t = t.next
    })
    return l.next
}

链表转变成数组方法如下所示:

export function ListToInts(head: ListNode | null):number[] {
    const arr = []
    while (head !== null) {
      arr.push(head.val)
      head = head.next
    }
    return arr
}

测试代码如下所示:

import { expect } from 'chai'
import { mergeTwoLists, mergeTwoLists1 } from './index'
import { IntsToList, ListToInts } from '../../structures/ListNode'

describe('0021.Merge-Two-Lists', function () {
    describe('mergeTwoLists', function () {
        it('l1 = [1,2], l2 = [3,4], should return [1,2,3,4]', function () {
            expect(mergeTwoLists(IntsToList([1,2]), IntsToList([3,4]))).to.deep.equal(IntsToList([1,2,3,4]))
        })
    })
    describe('mergeTwoLists-1', function () {
        it('l1 = [], l2 = [0], should return [0]', function () {
            const l1 = IntsToList([])
            const l2 = IntsToList([0])
            const result = mergeTwoLists1(l1, l2)
            const resultArray = ListToInts(result)
            expect(resultArray).to.deep.equal([0])
        })
    })
})