Start learning free

LESSON 297 OF 409 · LINKED LISTS

Remove Linked List Elements in O(n) Time Complexity using C++

Practice O(n) Read the full explanation

Given the head of a singly linked list and an integer, remove all the nodes of the linked list whose value equals that integer, and return the new head.

Example:

Input: head = [1, 2, 6, 3, 4, 5, 6], integer = 6
Output: [1, 2, 3, 4, 5]


Note:

Your algorithm should run in O(n) time and use O(1) extra space.

STEP 1 OF 8
    Ctrl + Enter to check

    C++ · LINKED LISTS

    Remove Linked List Elements in C++, explained

    Understanding the Problem

    The core challenge of this problem is to traverse the linked list and remove nodes that match the given value without disrupting the structure of the list. This problem is significant in various applications such as data cleaning, where unwanted elements need to be removed efficiently.

    Potential pitfalls include handling edge cases such as an empty list, all nodes having the target value, or the target value not being present in the list.

    Approach

    To solve this problem, we can use a single pass through the linked list, which ensures an O(n) time complexity. We will maintain a pointer to the current node and a pointer to the previous node to help with node removal.

    Here is a step-by-step approach:

    1. Initialize a dummy node that points to the head of the list. This helps handle edge cases where the head itself needs to be removed.
    2. Use two pointers: one for the current node and one for the previous node.
    3. Traverse the list. If the current node's value matches the target value, adjust the previous node's next pointer to skip the current node.
    4. Otherwise, move the previous pointer to the current node.
    5. Move the current pointer to the next node.
    6. Return the next node of the dummy node as the new head of the list.

    Algorithm

    Here is a detailed breakdown of the algorithm:

    1. Create a dummy node and set its next pointer to the head of the list.
    2. Initialize two pointers: prev (pointing to the dummy node) and curr (pointing to the head).
    3. While curr is not null:
      • If curr's value equals the target value, set prev's next to curr's next.
      • Otherwise, move prev to curr.
      • Move curr to the next node.
    4. Return dummy's next as the new head of the list.

    Code Implementation

    
    #include <iostream>
    using namespace std;
    
    // 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) {
            // Create a dummy node that points to the head
            ListNode* dummy = new ListNode(0, head);
            ListNode* prev = dummy;
            ListNode* curr = head;
            
            // Traverse the list
            while (curr != nullptr) {
                if (curr->val == val) {
                    // Remove the current node
                    prev->next = curr->next;
                } else {
                    // Move prev to curr
                    prev = curr;
                }
                // Move curr to the next node
                curr = curr->next;
            }
            
            // Return the new head
            ListNode* newHead = dummy->next;
            delete dummy; // Free the dummy node
            return newHead;
        }
    };
    
    // Helper function to print the list
    void printList(ListNode* head) {
        while (head != nullptr) {
            cout << head->val << " ";
            head = head->next;
        }
        cout << endl;
    }
    
    // Main function to test the solution
    int main() {
        // Create a linked list: 1 -> 2 -> 6 -> 3 -> 4 -> 5 -> 6
        ListNode* head = new ListNode(1);
        head->next = new ListNode(2);
        head->next->next = new ListNode(6);
        head->next->next->next = new ListNode(3);
        head->next->next->next->next = new ListNode(4);
        head->next->next->next->next->next = new ListNode(5);
        head->next->next->next->next->next->next = new ListNode(6);
        
        // Print the original list
        cout << "Original list: ";
        printList(head);
        
        // Remove elements with value 6
        Solution solution;
        head = solution.removeElements(head, 6);
        
        // Print the modified list
        cout << "Modified list: ";
        printList(head);
        
        return 0;
    }
    

    Complexity Analysis

    The time complexity of this approach is O(n), where n is the number of nodes in the linked list. This is because we traverse the list once. The space complexity is O(1) as we are using only a few extra pointers and not any additional data structures.

    Edge Cases

    Consider the following edge cases:

    • An empty list: The function should return null.
    • All nodes have the target value: The function should return null.
    • No nodes have the target value: The function should return the original list.

    These cases are handled by the algorithm as it traverses the entire list and adjusts pointers accordingly.

    Testing

    To test the solution comprehensively, consider the following test cases:

    • Empty list: []
    • List with all nodes having the target value: [6, 6, 6]
    • List with no nodes having the target value: [1, 2, 3]
    • List with some nodes having the target value: [1, 2, 6, 3, 4, 5, 6]

    Use a variety of test cases to ensure the solution handles all scenarios correctly.

    Thinking and Problem-Solving Tips

    When approaching such problems, consider the following tips:

    • Understand the problem requirements and constraints thoroughly.
    • Think about edge cases and how to handle them.
    • Break down the problem into smaller steps and solve each step methodically.
    • Practice solving similar problems to improve your problem-solving skills.

    Conclusion

    In this blog post, we discussed how to remove elements from a linked list in O(n) time complexity using C++. We covered the problem definition, approach, algorithm, code implementation, complexity analysis, edge cases, and testing. Understanding and solving such problems is crucial for improving your coding skills and preparing for technical interviews.

    Additional Resources

    For further reading and practice, consider the following resources:

    Keep going with C++About 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free