Easy
题目描述
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回新的头节点。
示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
示例 2:
输入:head = [], val = 1
输出:[]
示例 3:
输入:head = [7,7,7,7], val = 7
输出:[]
提示:
- 列表中的节点数目在范围
[0, 10^4]内 1 <= Node.val <= 500 <= val <= 50
解题思路
这道题要求删除链表中所有值等于指定值的节点。主要有两种解法:
解法一:哨兵节点(推荐)
创建一个哨兵节点指向原链表头部,这样可以统一处理删除头节点和非头节点的情况。维护两个指针:prev指向待检查节点的前一个节点,curr指向当前检查的节点。如果当前节点值等于目标值,则让prev.next指向curr.next来删除当前节点;否则移动prev指针。
解法二:递归
递归地处理当前节点的后续链表,然后判断当前节点是否需要删除。如果当前节点值等于目标值,则返回处理后的后续链表;否则将当前节点连接到处理后的后续链表并返回。
解法三:直接遍历
不使用哨兵节点,先处理头部连续的目标值节点,然后遍历剩余链表删除目标节点。需要特别处理头节点的情况。
哨兵节点解法思路清晰,代码简洁,是最推荐的方法。
代码实现
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode dummy(0);
dummy.next = head;
ListNode* prev = &dummy;
ListNode* curr = head;
while (curr != nullptr) {
if (curr->val == val) {
prev->next = curr->next;
} else {
prev = curr;
}
curr = curr->next;
}
return dummy.next;
}
};
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
dummy = ListNode(0)
dummy.next = head
prev = dummy
curr = head
while curr:
if curr.val == val:
prev.next = curr.next
else:
prev = curr
curr = curr.next
return dummy.next
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int val=0, ListNode next=null) {
* this.val = val;
* this.next = next;
* }
* }
*/
public class Solution {
public ListNode RemoveElements(ListNode head, int val) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode prev = dummy;
ListNode curr = head;
while (curr != null) {
if (curr.val == val) {
prev.next = curr.next;
} else {
prev = curr;
}
curr = curr.next;
}
return dummy.next;
}
}
var removeElements = function(head, val) {
let dummy = new ListNode(0);
dummy.next = head;
let prev = dummy;
let current = head;
while (current !== null) {
if (current.val === val) {
prev.next = current.next;
} else {
prev = current;
}
current = current.next;
}
return dummy.next;
};
复杂度分析
| 复杂度 | 哨兵节点解法 | 递归解法 |
|---|---|---|
| 时间复杂度 | O(n) | O(n) |
| 空间复杂度 | O(1) | O(n) |
- 时间复杂度:需要遍历整个链表一次
- 空间复杂度:哨兵节点解法只使用常数额外空间;递归解法需要O(n)的调用栈空间