Remove Linked List Elements#
Problem statement#
[1]You are given the starting node, head
, of a linked list, and an integer val
. Your task is to eliminate all nodes from the linked list that have a value equal to val
. After removing these nodes, return the new starting node of the modified linked list.
Example 1#
Input: head = [1,2,6,3,4,5,6], val = 6
Output: [1,2,3,4,5]
Example 2#
Input: head = [], val = 1
Output: []
Example 3#
Input: head = [7,7,7,7], val = 7
Output: []
Constraints#
The number of nodes in the list is in the range
[0, 10^4]
.1 <= Node.val <= 50
.0 <= val <= 50
.
Linked list data structure#
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) {}
};
Solution 1: Consider the special case for head#
Removing a node A
in a linked list means instead of connecting the previous node A.pre
to A
, you connect A.pre
to A.next
.
Code#
#include <iostream>
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) {}
};
ListNode* removeElements(ListNode* head, int val) {
// remove head if its value matches val
while (head && head->val == val) {
head = head->next;
}
if (head == nullptr) return nullptr;
ListNode* pre = head;
while (pre->next) {
if (pre->next->val == val) {
// remove pre->next
pre->next = pre->next->next;
} else {
pre = pre->next;
}
}
return head;
}
void print(const ListNode* head) {
ListNode* node = head;
std::cout << "[";
while (node) {
std::cout << node->val << ",";
node = node->next;
}
std::cout << "]\n";
}
int main() {
ListNode sixb(6);
ListNode five(5, &sixb);
ListNode four(4, &five);
ListNode three(3, &four);
ListNode sixa(6, &three);
ListNode two(2, &sixa);
ListNode head(1, &two);
ListNode* newHead = removeElements(&head, 6);
print(newHead);
newHead = removeElements(nullptr, 1);
print(newHead);
ListNode seven4(7);
ListNode seven3(7, &seven4);
ListNode seven2(7, &seven3);
ListNode seven1(7, &seven2);
newHead = removeElements(&seven1, 7);
print(newHead);
}
Output:
[1,2,3,4,5,]
[]
[]
This solution efficiently removes nodes with a specified value val
from a linked list by using two pointers (head
and pre
) to traverse the list and update the next
pointers to bypass nodes with the specified value.
Complexity#
Runtime:
O(N)
, whereN
is the number of nodes.Memory:
O(1)
.
Solution 2: Create a previous dummy node for head#
head
has no pre
. You can create a dummy node for head.pre
whose values is out of the contraints.
Code#
#include <iostream>
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) {}
};
ListNode* removeElements(ListNode* head, int val) {
// create a new head of value 2023 > 50
ListNode preHead(2023, head);
ListNode* pre = &preHead;
while (pre->next) {
if (pre->next->val == val) {
pre->next = pre->next->next;
} else {
pre = pre->next;
}
}
return preHead.next;
}
void print(const ListNode* head) {
ListNode* node = head;
std::cout << "[";
while (node) {
std::cout << node->val << ",";
node = node->next;
}
std::cout << "]\n";
}
int main() {
ListNode sixb(6);
ListNode five(5, &sixb);
ListNode four(4, &five);
ListNode three(3, &four);
ListNode sixa(6, &three);
ListNode two(2, &sixa);
ListNode head(1, &two);
ListNode* newHead = removeElements(&head, 6);
print(newHead);
newHead = removeElements(nullptr, 1);
print(newHead);
ListNode seven4(7);
ListNode seven3(7, &seven4);
ListNode seven2(7, &seven3);
ListNode seven1(7, &seven2);
newHead = removeElements(&seven1, 7);
print(newHead);
}
Output:
[1,2,3,4,5,]
[]
[]
This solution creates a preHead
node with a value of 2023
(an arbitrary value larger than 50
) and sets its next
pointer to point to the original head
of the linked list.
The purpose of this preHead
node is to serve as the dummy or sentinel node at the beginning of the linked list. Having a preHead
node simplifies the code because it eliminates the need to handle the special case of removing nodes from the beginning of the list separately.
The remaining code is the same.
Complexity#
Runtime:
O(N)
, whereN
is the number of nodes.Memory:
O(1)
.
Attention!#
Depending on your real situation, in practice, you might need to deallocate memory for the removed nodes; especially when they were allocated by the new
operator.
ListNode* removeElements(ListNode* head, int val) {
ListNode preHead(2022, head);
ListNode* pre = &preHead;
while (pre->next) {
if (pre->next->val == val) {
ListNode* node = pre->next;
pre->next = node->next;
delete node;
} else {
pre = pre->next;
}
}
return preHead.next;
}
Key takeaway#
In some linked list problems where
head
needs to be treated as a special case, you can create a previous dummy node for it to adapt the general algorithm.Be careful with memory leak when removing nodes of the linked list containing pointers.
Exercise#
Delete Node in a Linked List[2].