Remove Zero Sum Consecutive Nodes from Linked List

Updated on 10 July, 2025
Remove Zero Sum Consecutive Nodes from Linked List header image

Problem Statement

In this task, we have a linked list where each node can have any integer value between -1000 and 1000. The challenge is to repeatedly identify sequences (or sublists) of consecutive nodes that sum up to zero and remove such sequences. We repeat this process until no further sequences that sum to zero are left in the linked list. After the final operation, we then return the modified linked list which represents the final result, devoid of any such zero-sum sub-sequences. This problem is akin to cleansing the list by eliminating elements that together negate each other to zero, thereby simplifying the list to those elements contributing to a non-zero cumulative effect.

Examples

(Note that in the examples below, all sequences are serializations of ListNode objects.)

Example 1

Input:

head = [1,2,-3,3,1]

Output:

[3,1]

Note:

The answer [1,2,1] would also be accepted.

Example 2

Input:

head = [1,2,3,-3,4]

Output:

[1,2,4]

Example 3

Input:

head = [1,2,3,-3,-2]

Output:

[1]

Constraints

  • The given linked list will contain between 1 and 1000 nodes.
  • Each node in the linked list has -1000 <= node.val <= 1000.

Approach and Intuition

In solving the problem of deleting consecutive sequences which sum to 0, we can utilize a prefix-sum or prefix balance mechanism along with a hash table (or dictionary) that helps us identify previously seen sums:

  1. As we iterate over the list, calculate the cumulative or prefix sum up to each node.
  2. Store each sum in a hashmap where the key is the cumulative sum and the value is the node corresponding to that cumulative sum.
  3. If we encounter a cumulative sum that has been seen before, it means the elements in-between these two occurrences sum to zero (because the cumulative impact between them hasn't changed the sum). In such cases:
    • We can skip all the nodes from the first instance after where this sum was observed up to the current node. This is because all these intermediate values together result in a zero sum.
    • Reset pointers and possibly remove entries from the hashmap for sums that get invalidated or skipped due to node removal.
  4. We also need special attention for sequences beginning from the head itself that sum to zero. For handling these cases, we may start from a dummy node which initially has a zero cumulative sum.

Overall, this problem explores the utilization of cumulative sums and efficient look-up structures (like hashmaps) to achieve desired modifications in the linked list. The need to iterate over and modify the linked list multiple times underscores the complexity arising from dynamically changing data structures and the need for efficient management of linked list operations.

Thus, the use of prefix-sum with a mapping technique allows efficient discovery and deletion of zero-sum sublists, enhancing our ability to iterate and modify linked lists dynamically.

Solutions

  • C++
cpp
class Solution {
public:
    ListNode* eraseZeroSumSublists(ListNode* head) {
        ListNode* dummy = new ListNode(0, head);
        ListNode* current = dummy;
        int cumulativeSum = 0;
        unordered_map<int, ListNode*> sumToNodeMap;
        sumToNodeMap[0] = dummy;
    
        // Populate map with current node for each prefix sum encountered
        while (current != nullptr) {
            cumulativeSum += current->val;
            sumToNodeMap[cumulativeSum] = current;
            current = current->next;
        }
    
        // Reinitialize for second pass
        cumulativeSum = 0;
        current = dummy;
    
        // Adjust next pointers to skip zero sum sublists
        while (current != nullptr) {
            cumulativeSum += current->val;
            current->next = sumToNodeMap[cumulativeSum]->next;
            current = current->next;
        }
            
        return dummy->next;
    }
};

The given C++ code provides a solution for removing consecutive nodes from a linked list that sum up to zero. This operation uses a two-pass approach with the help of a hash map to track the cumulative sums of the nodes.

  • Utilize a dummy node to facilitate edge cases involving the head of the list.

  • In the first traversal of the linked list:

    1. Maintain a cumulative sum of node values.
    2. Map each cumulative sum to the latest corresponding node using an unordered_map.
  • In the second traversal:

    1. Use the map to skip over nodes that form a zero sum sublist.
    2. For each cumulative sum found in the map, set the next pointer of the current node to the node mapped to the next encountered cumulative sum.

The procedure ensures that all sublists with a cumulative sum of zero are effectively removed from the linked list. Adjusting the next pointers in the second pass modifies the linked list in place, resulting in no zero sum consecutive sublists in the final linked list structure.

  • Java
java
class Solution {
    public ListNode deleteZeroSumSequences(ListNode head) {
        ListNode dummy = new ListNode(0, head);
        ListNode temp = dummy;
        int cumulativeSum = 0;
        Map<Integer, ListNode> sumMap = new HashMap<>();
        sumMap.put(0, dummy);
    
        while (temp != null) {
            cumulativeSum += temp.val;
            sumMap.put(cumulativeSum, temp);
            temp = temp.next;
        }
    
        cumulativeSum = 0;
        temp = dummy;
    
        while (temp != null) {
            cumulativeSum += temp.val;
            temp.next = sumMap.get(cumulativeSum).next;
            temp = temp.next;
        }
        return dummy.next; 
    }
}

The provided Java function deleteZeroSumSequences() within the Solution class addresses the problem of removing consecutive sequences of nodes in a linked list whose sums equal zero. Follow the implementation steps and logic to understand this solution:

  1. Initialize a dummy node pointing to the head. This helps in handling edge cases smoothly.

  2. Initialize cumulativeSum to keep track of the summed value of nodes as the list is traversed.

  3. Use a HashMap sumMap to store cumulative sums and corresponding nodes. Initially, add the sum 0 and the dummy node into this map.

  4. Traverse the linked list from the dummy node, and for each node,

    • Update cumulativeSum with the value of the current node.
    • Add this cumulativeSum and the current node to sumMap. If cumulativeSum was previously in the map, updating it ensures the furthest occurrence of this sum remains stored.
  5. Reset cumulativeSum to 0 and start the traversal of the list again from the dummy node.

  6. In this second pass,

    • Increment cumulativeSum by the value of the current node.
    • Direct the next pointer of the current node to the next of the node associated with cumulativeSum in sumMap. This effectively skips over nodes that form a zero-sum sequence.
    • Continue to the next node.
  7. Finally, return the next node of the dummy, which points to the modified list head.

By leveraging the HashMap to track sums, this method efficiently identifies and removes nodes involved in zero-sum sequences without requiring nested loops, leading to an optimal solution in handling the problem straightforwardly.

  • Python
python
class Solution:
    def removeZeroSumSublists(self, head: Optional[ListNode]) -> Optional[ListNode]:
        initial_node = ListNode(0, head)
        cursor = initial_node
        sum_accumulated = 0
        sum_to_node_map = {0: initial_node}
    
        # Traverse and map cumulative sums to their corresponding nodes
        while cursor is not None:
            sum_accumulated += cursor.val
            sum_to_node_map[sum_accumulated] = cursor
            cursor = cursor.next
    
        # Reset for second pass
        sum_accumulated = 0
        cursor = initial_node
    
        # Adjust links to skip zero-sum sequences
        while cursor is not None:
            sum_accumulated += cursor.val
            cursor.next = sum_to_node_map[sum_accumulated].next
            cursor = cursor.next
    
        return initial_node.next

The provided Python solution utilizes a two-pass approach to solve the problem of removing consecutive nodes from a linked list that sum up to zero. Follow the steps and the logic below to understand how the solution works:

  1. Define a new ListNode named initial_node that acts as a pseudo head for ease of manipulation. This node points to the actual head of the linked list.
  2. Define a cursor initialized at initial_node, and a variable sum_accumulated to keep track of the cumulative sum of node values.
  3. Utilize a dictionary sum_to_node_map to map each cumulative sum to its corresponding node. This mapping helps in finding the start point of zero sum subsequences quickly.
  4. Start the first pass by traversing through the linked list:
    • For each node, add its value to sum_accumulated.
    • Update sum_to_node_map with the current sum_accumulated as key and the current node as value. This step ensures that the most recent node for each cumulative sum is recorded.
  5. After completing the first pass, reset sum_accumulated to zero and re-position the cursor to initial_node for the second pass.
  6. In the second pass, adjust the next pointers of nodes in the list:
    • Incrementally add the value of each node to sum_accumulated.
    • Directly link the next pointer of the current cursor to the node mapped in sum_to_node_map for the current sum_accumulated. This crucial step effectively skips over all nodes that together sum to zero since their cumulative sum would appear again in sum_to_node_map, linking past them.
  7. Finally, return initial_node.next, which points to the head of the modified list.

This solution efficiently identifies and removes zero-sum sequences by leveraging cumulative sums and mappings without needing nested iterations. Ensure understanding and careful handling of updating node links and managing edge cases, such as multiple consecutive zero-sum sequences and sequences at the start of the list.

Comments

No comments yet.