3217. Delete Nodes From Linked List Present in Array
Problem Description
You are given an array of integers nums
and the head
of a linked list. The task is to return the head
of the modified linked list after removing all nodes from the linked list that have a value that exists in nums
.
Intuition
To efficiently remove nodes with values present in nums
, we leverage a hash table to store all the values from nums
for quick lookup. We utilize a dummy node to simplify edge cases, such as when the head itself needs to be removed.
We iterate through the linked list, and for each node, we check if its value exists in the hash table. If the value is present, we adjust the current node's pointer to skip the node with that value, effectively removing it from the list. If the value is not present, we move the pointer to the next node. This ensures that only nodes with values not in nums
remain in the list. Finally, we return the next node after the dummy node, which represents the head of the modified list.
Learn more about Linked List patterns.
Solution Approach
Solution 1: Hash Table
The solution uses a hash table to efficiently remove unwanted nodes from the linked list. Here is a step-by-step breakdown of the approach:
-
Create a Hash Table: Convert the array
nums
into a set,s
, so that we can quickly check if a node's value is one that needs to be removed. This conversion operation takesO(n)
time, wheren
is the size ofnums
. -
Initialize a Dummy Node: Define a dummy node
dummy
that points to the head of the linked list. The dummy node is utilized to handle edge cases smoothly, like when the head node itself needs to be removed. -
Traverse the Linked List: Start traversing the linked list from the dummy node. Use a pointer
pre
, initialized to the dummy, to keep track of the node we're currently examining.- Check and Remove Node: As we visit each node, check if the value of the next node (
pre.next.val
) exists in the sets
.- If it does, update
pre.next
to skip over the unwanted node (pre.next = pre.next.next
), effectively removing it from the list. - If it doesn't, simply advance the
pre
pointer to the next node.
- If it does, update
- Check and Remove Node: As we visit each node, check if the value of the next node (
-
Return the Modified List: After traversing the list, the linked list is now stripped of nodes whose values exist in
nums
. Returndummy.next
, which points to the head of the modified list.
The code implements this approach concisely:
class Solution:
def modifiedList(
self, nums: List[int], head: Optional[ListNode]
) -> Optional[ListNode]:
s = set(nums)
pre = dummy = ListNode(next=head)
while pre.next:
if pre.next.val in s:
pre.next = pre.next.next
else:
pre = pre.next
return dummy.next
This method runs at O(m + n)
time complexity, where m
is the length of the linked list and n
is the length of nums
, with an O(n)
space complexity due to the hash table.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through an example where nums = [2, 3]
and the linked list has the values 1 -> 2 -> 3 -> 4
.
-
Initial Setup:
- Create a set from
nums
:s = {2, 3}
for fast look-up. - Initialize a dummy node
dummy
which points to the head of the linked list. This will help manage edge cases. - Set pointer
pre
todummy
.
- Create a set from
-
Traverse the Linked List:
-
Start at the node with value
1
(which isdummy.next
):- Check if
1
is in the sets
. It is not. - Move
pre
to the next node (value1
).
- Check if
-
Move to the next node with value
2
:2
is in sets
.- Remove this node by setting
pre.next
topre.next.next
, skipping node2
. - The list now looks like
1 -> 3 -> 4
.
-
Move to the next node (after
1
), now3
:3
is in sets
.- Remove this node by setting
pre.next
topre.next.next
, skipping node3
. - The list is now
1 -> 4
.
-
Move to the next node (after
1
), now4
:4
is not in sets
.- Move
pre
to this node (value4
).
-
-
Finished Traversal:
- The final linked list is
1 -> 4
.
- The final linked list is
-
Return the Modified List:
- Return
dummy.next
which points to1
, the head of the modified linked list.
- Return
The final output is the list 1 -> 4
, with nodes containing values from nums
removed.
Solution Implementation
1from typing import List, Optional
2
3# Definition for singly-linked list.
4class ListNode:
5 def __init__(self, val=0, next=None):
6 self.val = val
7 self.next = next
8
9class Solution:
10 def modifiedList(self, nums: List[int], head: Optional[ListNode]) -> Optional[ListNode]:
11 # Convert list of numbers to a set for O(1) average-time complexity lookups
12 value_set = set(nums)
13
14 # Create a dummy node that points to the head of the list
15 dummy = ListNode(0)
16 dummy.next = head
17
18 # Use 'curr' to traverse and 'prev' for maintaining the connection of nodes
19 prev = dummy
20 curr = head
21
22 # Traverse the linked list
23 while curr:
24 # If the value of the current node is in the set, remove the node
25 if curr.val in value_set:
26 prev.next = curr.next
27 else:
28 # Move 'prev' to 'curr' only if no deletion occurs
29 prev = curr
30
31 # Always move 'curr' to the next node in the list
32 curr = curr.next
33
34 # Return the head of the modified list
35 return dummy.next
36
1import java.util.HashSet;
2import java.util.Set;
3
4// Definition for singly-linked list.
5public class ListNode {
6 int val;
7 ListNode next;
8
9 // Default constructor
10 ListNode() {}
11
12 // Constructor with value initialization
13 ListNode(int val) {
14 this.val = val;
15 }
16
17 // Constructor with value and next node initialization
18 ListNode(int val, ListNode next) {
19 this.val = val;
20 this.next = next;
21 }
22}
23
24class Solution {
25 // Method to modify the linked list by removing nodes that have values present in the nums array
26 public ListNode modifiedList(int[] nums, ListNode head) {
27 Set<Integer> valueSet = new HashSet<>();
28
29 // Add all elements of the array nums to a HashSet for quick lookup
30 for (int number : nums) {
31 valueSet.add(number);
32 }
33
34 // Create a dummy node to simplify edge cases where removal is needed at the head
35 ListNode dummy = new ListNode(0, head);
36
37 // Iterate through the linked list using 'pre' as a pointer to the node before the current
38 for (ListNode pre = dummy; pre.next != null;) {
39 // If the current node's value is in the set, remove it by skipping over it
40 if (valueSet.contains(pre.next.val)) {
41 pre.next = pre.next.next;
42 } else {
43 // Otherwise, move the 'pre' pointer to the next node
44 pre = pre.next;
45 }
46 }
47
48 // Return the new head of the list, which is next to the dummy node
49 return dummy.next;
50 }
51}
52
1#include <vector>
2#include <unordered_set>
3
4/**
5 * Definition for singly-linked list.
6 */
7struct ListNode {
8 int val; // Value of the list node
9 ListNode *next; // Pointer to the next list node
10
11 // Default constructor initializing with zero and nullptr
12 ListNode() : val(0), next(nullptr) {}
13
14 // Constructor to initialize node with a given value and nullptr
15 ListNode(int x) : val(x), next(nullptr) {}
16
17 // Constructor to initialize node with a given value and pointer to the next node
18 ListNode(int x, ListNode *next) : val(x), next(next) {}
19};
20
21class Solution {
22public:
23 /**
24 * This function modifies the input linked list by removing nodes that contain
25 * values present in the given vector `nums`.
26 *
27 * @param nums Vector of integers whose values need to be removed from the list.
28 * @param head Pointer to the head of the singly-linked list.
29 * @return Pointer to the head of the modified linked list.
30 */
31 ListNode* modifiedList(std::vector<int>& nums, ListNode* head) {
32 // Create a set with elements from nums for efficient lookup
33 std::unordered_set<int> values_set(nums.begin(), nums.end());
34
35 // Dummy node to handle edge cases easily (like deletion of the head node)
36 ListNode* dummy = new ListNode(0, head);
37
38 // Pointer to traverse the list, initially pointing to dummy node
39 ListNode* prev = dummy;
40
41 // Traverse the linked list
42 while (prev->next) {
43 // If the next node's value is in the set, skip the node by changing pointers
44 if (values_set.count(prev->next->val)) {
45 prev->next = prev->next->next;
46 } else {
47 // Otherwise, move prev pointer forward
48 prev = prev->next;
49 }
50 }
51
52 // Return the head of the modified list, which is next of dummy node
53 return dummy->next;
54 }
55};
56
1/**
2 * Definition for singly-linked list node.
3 */
4class ListNode {
5 val: number;
6 next: ListNode | null;
7
8 constructor(val?: number, next?: ListNode | null) {
9 this.val = (val === undefined ? 0 : val);
10 this.next = (next === undefined ? null : next);
11 }
12}
13
14/**
15 * Modifies the linked list based on the values present in the nums array.
16 * Removes nodes from the linked list that contain values present in the nums array.
17 *
18 * @param nums - Array of numbers to be removed from the linked list.
19 * @param head - Head of the original linked list.
20 * @returns - New head of the modified linked list.
21 */
22function modifiedList(nums: number[], head: ListNode | null): ListNode | null {
23 // Create a set from nums to quickly check for existence.
24 const valuesToRemove: Set<number> = new Set(nums);
25
26 // Initialize a dummy node that points to the head.
27 const dummy: ListNode = new ListNode(0, head);
28
29 // Iterate through the linked list.
30 for (let currentPointer = dummy; currentPointer.next; ) {
31 // If the value of the next node exists in the set, remove the node.
32 if (valuesToRemove.has(currentPointer.next.val)) {
33 currentPointer.next = currentPointer.next.next;
34 } else {
35 // Otherwise, move the pointer forward.
36 currentPointer = currentPointer.next;
37 }
38 }
39
40 // Return the new head of the list, which is the next of the dummy node.
41 return dummy.next;
42}
43
Time and Space Complexity
The time complexity of the code is O(n + m)
, where n
is the length of the array nums
and m
is the length of the linked list head
. This is because creating the set s
from nums
requires O(n)
time, and iterating through the linked list requires O(m)
time.
The space complexity of the code is O(n)
. This stems from the creation of the set s
, which stores the unique elements from the array nums
, requiring O(n)
additional space.
Learn more about how to find time and space complexity quickly.
You are given an array of intervals where intervals[i] = [start_i, end_i]
represent the start and end of the ith
interval. You need to merge all overlapping intervals and return an array of the non-overlapping intervals that cover all the intervals in the input.
Recommended Readings
Linked List Cycle Given a linked list with potentially a loop determine whether the linked list from the first node contains a cycle in it For bonus points do this with constant space Parameters nodes The first node of a linked list with potentially a loop Result Whether there is a loop contained
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!