𝔩𝔢𝔩𝕠𝔭𝔢𝔷
Connect With Me on LinkedIn

Python Study

Removing Duplicates

Mastering Duplicate Removal in Sorted Linked Lists with Python

Introduction

Removing duplicates from a sorted linked list is a fundamental operation in data structure manipulation. This problem tests one's ability to traverse and modify linked structures efficiently. In this article, we'll explore various approaches to solve this problem in Python, focusing on in-place modifications and maintaining the list's sorted nature.

Problem Statement

Given:

  • The head of a singly linked list whose nodes are in sorted order with respect to their values

Objective:

  • Modify the list in place to remove any nodes with duplicate values
  • Maintain the sorted order of the list

Example:

  • Input: 1 -> 1 -> 3 -> 4 -> 4 -> 4 -> 5 -> 6 -> 6
  • Output: 1 -> 3 -> 4 -> 5 -> 6

Assumption:

  • Each LinkedList node has an integer value and a next node pointing to the next node in the list or to None if it's the tail of the list

Strategy and Hypothesis

To solve this problem, we need to compare adjacent nodes:

  • If the current node's value is greater than the previous node's value, we keep it and move forward
  • Otherwise, we skip the current node by updating the previous node's next pointer

This approach can be implemented both iteratively and recursively, with each method offering unique insights into linked list manipulation.

Implementation

Initial Attempt: Iterative Approach

class LinkedList:
    def __init__(self, value):
        self.value = value
        self.next = None

def removeDuplicatesFromLinkedList(linkedList):
    prevNode = linkedList
    currNode = linkedList.next

    while prevNode is not None:
        if currNode is None:
            prevNode.next = None
            break

        if currNode.value > prevNode.value:
            prevNode.next = currNode
            prevNode = currNode
            currNode = currNode.next
        else:
            currNode = currNode.next

    return linkedList

This iterative approach correctly handles duplicate removal but can be further optimized.

Improved Approach: Optimized Recursive Solution

class LinkedList:
    def __init__(self, value):
        self.value = value
        self.next = None

def removeDuplicatesFromLinkedList(linkedList):
    validateLink(linkedList)
    return linkedList

def validateLink(node):
    if node is None or node.next is None:
        return

    if node.value == node.next.value:
        node.next = node.next.next
        validateLink(node)
    else:
        validateLink(node.next)

This recursive approach provides a cleaner solution by looking forward at the list, simplifying the logic, and reducing the number of comparisons.

Optimization Analysis

Space Complexity

  • Iterative Approach: O(1) space complexity, as it uses a constant amount of extra space regardless of input size.
  • Recursive Approach: O(n) space complexity in the worst case due to the call stack, where n is the number of nodes in the list.

Time Complexity

Both approaches have O(n) time complexity, where n is the number of nodes in the list:

  • Iterative: Traverses the list once, performing constant-time operations at each node.
  • Recursive: Makes at most n recursive calls, each performing constant-time operations.

Optimal Space & Time

The iterative approach provides the best balance of space and time efficiency:

  • It uses constant extra space.
  • It requires only a single pass through the list.
  • It avoids potential stack overflow issues associated with recursion for very long lists.

However, the recursive approach offers a more elegant and concise solution, which might be preferable when code readability is prioritized over optimal space usage.

Key Takeaways

  1. In-place linked list modifications can be achieved through careful pointer manipulation.
  2. Recursive solutions can offer elegant implementations for linked list operations.
  3. The sorted nature of the input list significantly simplifies the duplicate removal process.
  4. Iterative solutions often provide better space efficiency for linked list operations.
  5. Visualizing the problem (e.g., as a series of resistors) can lead to intuitive solution strategies.

Conclusion

Removing duplicates from a sorted linked list demonstrates the importance of efficient traversal and modification techniques in data structure manipulation. While iterative and recursive approaches can solve the problem effectively, each offers unique advantages. The iterative method excels in space efficiency, while the recursive approach provides a cleaner, more elegant solution. This problem highlights the trade-offs between different implementation strategies, a common theme in algorithm design. As we tackle more complex linked list problems, the insights gained from this exercise—particularly in handling object references and choosing between iterative and recursive approaches—will prove invaluable in developing robust and efficient solutions.

Previous
Middle Node