这是我参与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的引用地址,当l1和l2链表皆有值时,比较两个链表的值
第一次比较,1 < 3,此时curr的next为ListNode { val: 1, next: ListNode { val: 2, next: null } },l1链表指针往后移动
第二次比较,2 < 3,此时curr的next为ListNode { val: 2, next: null },l1链表指针往后移动,指向null
第三次比较,由于l1已为null,跳出while循环,curr的next指向l2整个有序链表ListNode { val: 3, next: ListNode { val: 4, next: null } }
最后,返回节点head的next值,该值为ListNode { val: 1, next: ListNode { val: 2, next: ListNode { val: 3, next: [ListNode] } } }
head和curr的比喻关系
在一个房间内,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])
})
})
})