Small and smarter Python data structure: delete duplicate nodes of unordered linked list

Keywords: Python Programming github

Welcome to wechat public account: Python
Reply after attention: 1024, you can get selected programming learning e-books.

In the past two days, I have made a group with several friends to urge each other to learn. I want to urge myself to learn and also urge my original output. In fact, I am lazy for many times. I really have nothing to write. No, I have opened a new label daily programming problem in my free knowledge planet brief programming. Later, I will reconcile some problems encountered in my study and work. The resolution is recorded in it. There are some points that can be expanded. I will write them to wechat public account.
My goal is:

I wrote a simple rule, everyone said yes, then let's start. I am used to doing things one day ahead of time (if there is time).

Today, I will share with you the book "Python programmer interview algorithm dictionary", Chapter 1, Section 2: delete the duplicate nodes of the unordered list.

If you're reading it for the first time, maybe you can look at the following articles in this series:
Small and smarter Python data structure: linked list reversal

Today's problem

"""
//Goal: write a program to remove duplicates from the unordered list
//For example:
//Input - > 1 - > 0 - > 3 - > 1 - > 4 - > 5 - > 1 - > 8
//Output - > 1 - > 0 - > 3 - > 4 - > 5 - > 8
"""

"""
Goal: write a program to remove duplicates from the unordered list
For example:
Input - > 1 - > 0 - > 3 - > 1 - > 4 - > 5 - > 1 - > 8
Output - > 1 - > 0 - > 3 - > 4 - > 5 - > 8
"""

First of all, we write the basic operation of the linked list. In the a ﹐ 0 ﹐ base.py file, the definition class, initialization function and traversal function of the linked list are currently included. (leading node)

# -*- coding: utf-8 -*-
"""
@author = Cousin
@date = 2019-10-19
@Personal wechat public account : Jane said Python
"""


# Definition of linked list data structure
class ListNode:
    def __init__(self, x):
        self.data = x
        self.next = None


class ListOperation:

    # Initialize linked list according to linked list data
    @staticmethod
    def init_list(n_list):
        # Initializing a header pointer
        head = ListNode("head")
        cur = head
        for i in n_list:
            node = ListNode(i)
            cur.next = node
            cur = node  # Equivalent to cur = cur.next, move backward
        return head

    # Traversing linked list
    @staticmethod
    def ergodic_list(head):
        cur = head.next
        while cur:
            print(cur.data)
            cur = cur.next

Solving problems

Before starting the program, you need to import the basic operation package of the linked list written earlier.

from Linked_list.a_0_base import ListOperation
Method 1: recursive de duplication
"""
Method One: recursive de duplication

Core idea: before each traversal and de duplication, the sub linked list is de duplicated.
In this way, the de duplicated sub linked list will generate a sub linked list until recursion to the end node
 Point, start backtracking at this time. Each backtracking will complete the de duplication of a sub chain.
Until it goes back to the head node, the list is de duplicated.

Time complexity: O(N^2)
Space complexity: O(1)
"""
Code
def remove_duplicates_one(head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if not head.next:  # Empty list or traverse to the last node
        return head  # Return to the header node or start backtracking
    cur_node = head  # Record header node
    head.next = remove_duplicates_one(head.next)   # Recursion, traversal backward
    # print("cur UU node =, cur UU node. Data)
    # print("at this time, head =, head. Data)
    pointer = head.next  # Record subsequent nodes
    # print("at this time, pointer =, pointer. Data)
    # Ergodic search
    while pointer:   # Traverse the current child list
        if head.data == pointer.data:
            cur_node.next = pointer.next  # Delete the same node
            pointer = cur_node.next  # Move backward, traverse the sublist
        else:
            pointer = pointer.next  # Move backward, traverse the sublist
            cur_node = cur_node.next  # Current node backward
    # print("at this time, head =, head. Data)
    # print("____________________________")
    return head  # Return the current sub chain header node
Method 2: delete in sequence
"""
Method Two: delete in sequence

Core idea: if you find out method one, it's not hard to understand.
Directly use double loop, one slow pointer, one fast pointer, match to
 Delete the fast pointer when its data value is the same, and then continue
 Traverse the fast pointer until the end, and then move the slow pointer backward to continue traversing.

Time complexity: O(N^2)
Space complexity: O(1)
"""
Code
def remove_duplicates_two(head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if not head.next:  # Empty list or traverse to the last node
        return head  # Return to the header node or start backtracking
    slow_node = head.next  # Record slow pointer (outer loop)
    while slow_node:  # Outer traversal
        fast_node = slow_node.next  # Record fast pointer (inner traversal)
        cur_node = slow_node  # Record the current node for easy deletion
        while fast_node:  # Inner layer traversal
            if fast_node.data == slow_node.data:  # Find the node with the same value as slow node in the sub chain (duplicate value node)
                cur_node.next = fast_node.next  # Delete duplicate node (make the next of current node point to the next of duplicate node)
            else:
                cur_node = fast_node  # Move the current node backward and continue to traverse the sub chain
            fast_node = fast_node.next  # Move backward, continue to traverse the sub chain (fast pointer)
        slow_node = slow_node.next  # Backward, continue traversal (slow pointer)
    return head  # Return the current sub chain header node
Method 3: space for time
"""
Method Three: space for time

Core idea: build an auxiliary stack to record linked list data items, traverse linked list,
1. If the data item of the current node is in the auxiliary stack, delete the node.
2. If the current node data item is not in the auxiliary stack, the node data item
 Perform the stack operation
 3. Continue to traverse until the end of the traverse.

Auxiliary stack optional data types: primitive, list, dictionary, set
 The search time complexity of dictionary and collection is O(1), and there is hash table inside the dictionary.
(hash function + hash conflict table), so the search time complexity is O(1).
The internal implementation of collections in Python is a dictionary, so the time complexity of searching is also O(1).

Time complexity: O(N)
Space complexity: O(N)
"""
Code
def remove_duplicates_three(head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if not head.next:  # Empty list or traverse to the last node
        return head  # Return to the header node or start backtracking
    run_node = head.next.next  # Starting from the second node (because the first node must not have the problem of repetition)
    pre_node = head.next  # Record the first node, and then make the precursor node.
    dict_all = {pre_node.data: "node"}  # Directly add the first node data item to the dictionary, and give any key value to
    while run_node:  # Traversing linked list
        if run_node.data in dict_all:  # Judge whether the current traversal node value is in the dictionary
            pre_node.next = run_node.next  # Delete duplicate node (make the next of current node point to the next of duplicate node)
        else:  # If it is not in the dictionary, it will be pushed in the stack and the predecessor node will be moved backward.
            dict_all[run_node.data] = "node"
            pre_node = run_node
        run_node = run_node.next  # Backward moving traversal
    # print(dict_all)
    return head  # Return the current sub chain header node

Test code

# Of course, there may be other ways, such as building an auxiliary list
# You are welcome to say what you think

# Program entry, test function functions
if __name__ == "__main__":
    s0 = ListOperation()  # Initializing a basic operation object instance of linked list
    list_data = [1, 2, 3, 4, 2, 3, 9, 1]  # Initialization data of linked list
    head = s0.init_list(list_data)  # Initializing linked list, leading node
    s0.ergodic_list(head)  # Traverse print list before reversing
    # head = remove_duplicates_one(head)  # Test method 1: reverse chain list
    # head = remove_duplicates_two(head)  # Test method 2: reverse chain list
    head = remove_duplicates_three(head)  # Test method 3: reverse chain list
    print("---------------------")
    s0.ergodic_list(head)  # After reversal, traverse the print list

The code idea of this article comes from the book "Python programmer interview manual". Some of the code in the book has problems, which has been modified and added with rich comments for your study. Later, I will open source all the content to Github, including code, ideas, calculation diagrams (hand drawing or computer drawing). If there is enough time, I will record video.
I hope you can support me a lot.

Hello everyone, I'm the old watch
If you think this article is good, forward, leave a message and click like are the biggest support for me.

Welcome to wechat public account: Python
Reply after attention: 1024, you can get selected programming learning e-books.

Posted by JustinMs66 on Wed, 23 Oct 2019 22:49:38 -0700