在我自己的开发生涯中,其实用到链表的情况很少,但是不可否认的是,链表对于 插入、删除元素 比较频繁的场景,是有较大性能上的提升,所以我认为,对于链表这种数据结构,作为前端工程师的我们也应该熟练掌握,本篇文章就准备聊聊关于它的一道较为经典的算法题,废话不多说,开搞!

ppx2.jpg

什么是链表

在开始讲解算法题之前,我们先看看链表的定义与特征

qidai.jpeg

链表是一种 线性结构,它的每一个元素除了存放本身的值以外,还存放了 指向其他元素的指针,通过指针来将所有元素串联起来,与数组的区别有如下几点:

合并两个有序链表

在知道了链表的定义之后,我们来做下这道经典的 合并两个有序链表,题目如下:

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

我们从题目中可以提取中两个关键点

对于该题目,一共有两种解决方式

下面依次给出具体代码

双指针:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} list1
* @param {ListNode} list2
* @return {ListNode}
*/
var mergeTwoLists = function(list1, list2) {
if(list1 === null) return list2
if(list2 === null) return list1
const head = new ListNode(0)
let cur = head
while(list1 && list2) {
if(list1.val <= list2.val) {
cur.next = list1
list1 = list1.next
}else {
cur.next = list2
list2 = list2.next
}
cur = cur.next
}
if(!list1) {
cur.next = list2
}
if(!list2) {
cur.next = list1
}
return head.next
}

递归:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} list1
* @param {ListNode} list2
* @return {ListNode}
*/
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
}
}