一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 1 天,点击查看活动详情。
题目链接
题目描述
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
测试用例
示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
限制
- 列表中的节点数目在范围 [0, 104] 内
- 1 <= Node.val <= 50
- 0 <= val <= 50
题目分析
题目需要我们移除链表中,具备有给定值的节点。由题目提供的链表结构可以确认,这是一个单向链表,即只能从链表头一路遍历的最后,因此,我们需要一直持有链表头节点的引用
以链表 A -> B -> C 为例,如果我们需要移除节点 B,则需要修改节点 A 的 next 指向为 C。由于题目提供的链表特性,我们在遍历链表时,如果当前引用已经指向到了节点 B,则无法删除当前节点,我们需要提前一步判定下一个节点是否需要移除,判断的伪代码如下:
if (A.next.val == val){ // A.next 为 B,此刻
A.next = A.next.next; // 将 A.next 修改引用指向为 C
}
在上面的判断里修改了 A.next 的引用后,我们需要再次为 A.next.val 检查,确认 A 的 next 指向是否需要继续后移
代码实现
考虑一种特殊的情况,即上开头的节点就是需要我们移除的目标节点,那么链表就需要重置自己的头节点 head = head.next;等重置完成后,就需要为 head.next 做值的判断,这中间会夹杂着不少的判断,代码如下:
var removeElements = function(head, val) {
if (head == null) return head;
// 处理开头值相同的情况
while (head != null && head.val == val) {
head = head.next;
}
let node = head;
// 正式处理链表中间的目标节点
for (; node != null && node.next != null;) {
if (node.next.val == val) {
node.next = node.next.next;
} else {
node = node.next;
}
}
return head;
};
优化
上面的解法略显繁琐,我们可以在头结点之前再添加一个节点,寓意为链表的无含义起始节点 startNode 。随后可以使用上面分析的通用判断即可
/*
function ListNode(val, next) {
this.val = (val === undefined ? 0 : val)
this.next = (next === undefined ? null : next)
}
*/
var removeElements = function(head, val) {
let h = new ListNode(0, head),
node = h; // 给定一个通用的头结点
for (; node.next != null;) {
if (node.next.val == val) {
node.next = node.next.next;
} else {
node = node.next
}
}
return h.next;
};