# 2.1. Remove duplicates

## Write code to remove duplicates from an unsorted linked list. Follow up: solve it without a temporary buffer

> example: ll = [3,2,1,3]

## 2.1.1. First idea

Will try a temporary buffer first. I don't see how the implementation differs from a simple list with O(n). Starter code:

```java
class Node {
    Node next = null;
    int data;

    public Node(int d){
        data = d;
    }

    void appendToTail(int d){
        Node end = new Node(d);
        Node n = this;
        while (n.next != null){
            n = n.next;
        }
        n.next = end;
    }
}

Node a = new Node(3);
Node b = new Node(2);
Node c = new Node(1);
Node d = new Node(3);
a.appendTotail(b);
b.appendToTail(c);
c.appendToTail(d);
```

Then iterate through the nodes, keep a list of visited_numbers. if current node is in this list, remove element and point .next to the next element.

```java
void remove_duplicates(Node a){
    visited = new ArrayList();
    if (a == null){
        return;
    }
    visited.add(a.data);
    Node current = a;
    while(current.next != null){
        if (current.next.next == null){
            return;
        }
        if visited.contains(current.next.data){
            current.next = current.next.next;
            current = current.next.next;
        }
        else{
            current = current.next;
            visited.add(current.next.data);
        }
    }
    return;
}
```

Basically delegiting an element in a linked list is moving the .next of the previous node to the next (in a singly linked list). If the next node is null, that is, if the current node is the last one, then jus return. Ideally I'd return the head, first node. But can't be done in a single linked list.

## 2.1.2. Follow up: solve it without a temporary buffer

Temporary buffer I assume it's the array of visited numbers, or the temprary Node? I think temporary node. I can just reuse `a`?

```java
void remove_duplicates(Node a){
    visited = new ArrayList();
    if (a == null){
        return;
    }
    visited.add(a.data);
    while(a.next != null){
        if (a.next.next == null){
            return;
        }
        if visited.contains(a.next.data){
            a.next = a.next.next;
            a = a.next.next;
        }
        else{
            a = a.next;
            visited.add(a.next.data);
        }
    }
    return;
}
```

Which should work equally fine.

## Hints

### Hint 1

> Try using a hash table, should be able to do this in a single pass of the linked list

Haven't used a hash table but a set of visited numbers, and I already do it in a single pass of the linked list.

### Hint 2

> Without extra space, you need O(N<sup>2</sup>) time. Use two pointers, where the second one searches ahead of the first one

Why do I need O(N<sup>2</sup>) time... My implementation is O(N). Doing something wrong? I guess my second pointer is just called `a.next`. There must be something I'm missing

## Solution

In order to remove duplicates, need to track duplicates --> hash table.

Iterate through the linked list, adding each element to the hash table. If there's a duplicate element, remove it and continue iterating. O(N) time.

```java
void deleteDups(LinkedListNode n){
    HashSet<Integer> set = new HashSet<Integer>();
    LinkedListNode previous = null;
    while(n != null){
        if(set.contains(n.data)){
            previous.next = n.next;
        }
        else{
            set.add(n.data);
            previous = n;
        }
        n = n.next;
    }
}
```

### Follow up: no buffer allowed

Iterate with two pointers: current, iterating through the linked list, and runner, checking all subsequent nodes for duplicates.

```java
void deleteDups(LinkedListNode head){
    LinkedListNode current = head;
    while(current != null){
        /* Remove all future nodes with the same value */
        LinkedListNode runner = current;
        while(runner != null){
            if(runner.next.data == current.data){
                runner.next = runner.next.next;
            }
            else{
                runner = runner.next;
            }
        }
        current = current.next;
    }
}
```

Buffer meant HashTable, ok yes then we need to check all the linked list for each element in the linked list, hence O(N<sup>2</sup>) time.

Code runs in O(1) space, but (N<sup>2</sup>) time.

## Resources

* [Java solution](https://github.com/careercup/CtCI-6th-Edition/blob/master/Java/Ch%2002.%20Linked%20Lists/Q2_01_Remove_Dups/QuestionA.java)
* [C++ solution](https://github.com/careercup/CtCI-6th-Edition-cpp/blob/a68ba3e1c630a4d218ff1294f3eaf5aeced449ec/chapter-2-Linked-Lists/2-1-remove-dups.cpp)
* [Python solution](https://github.com/careercup/CtCI-6th-Edition-Python/blob/e6bc732588601d0a98e5b1bc44d83644b910978d/Chapter2/LinkedList.py)
