Design a structure which supports insertion and first non-repeating element in O(1) time
Last Updated :
31 Mar, 2023
Design a Data structure which supports insertion and first non-repeating element in O(1) time. Operations that are supported by the data structure:
- Insertion: Insert a element into the data structure.
- First non-repeating Element: First non-repeating element into the array.
Note: If there is no non-repeating element in the array then print -1.
Consider the following custom Data structure:
Insert(4): [4]
Insert(1): [4, 1]
Insert(4): [4, 1, 4]
First_Non_Repeating Element: 1
The idea is to use Doubly Linked List and a Hash-map to maintain the frequency of the elements of the array. Below is the use-cases of the Hash-map and Doubly-Linked List in this Data-structure:
- Doubly Linked-List: to keep track of the non-repeating elements in the array.
- Hash-map: To keep track of the occurrence of the elements and the address of non-repeating elements in the Doubly Linked-List
Below is the illustration of the operations:
- Insertion: Insert an element into the array and check the frequency of the element into the map. If it is previously occurred then remove the element from the Doubly Linked List with the help of the addresses stored in the hash-map. Finally, increase the occurrence of the element into the hash-map.
- First Non-repeating element: First Non-repeating element of the array will be the first element of the Doubly Linked List.
Advantages of this Data-structure:
- Insertion and First Non-repeating element in O(1) time.
Disadvantages of this Data-structure:
- Cannot Keep track of the order of the elements.
- Custom Data-structures will need custom Hasp-map to store the elements into the map.
- Memory Inefficient
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
struct node {
struct node* next;
struct node* prev;
int data;
};
struct node *head = NULL, *tail = NULL;
map< int , int > occurrences;
map< int , node*> address;
void insert( int value)
{
occurrences[value]++;
if (occurrences[value] == 1 &&
address.find(value) == address.end()) {
struct node* temp =
( struct node*) malloc ( sizeof ( struct node));
temp->next = NULL;
temp->prev = NULL;
temp->data = value;
address[value] = temp;
if (head == NULL)
{
head = temp;
tail = temp;
}
else
{
tail->next = temp;
temp->prev = tail;
tail = temp;
}
}
else if (occurrences[value] > 1 &&
address.find(value) != address.end()) {
struct node* temp = address[value];
address.erase(value);
if (temp == head) {
temp = head;
head = head->next;
free (temp);
}
else if (temp == tail) {
temp = tail;
tail->prev->next = NULL;
free (temp);
}
else {
temp->next->prev = temp->prev;
temp->prev->next = temp->next;
free (temp);
}
}
}
void findUniqueNumber()
{
if (head == NULL)
cout << "-1\n" ;
else
cout << head->data << "\n" ;
}
int main()
{
insert(4);
insert(1);
insert(4);
findUniqueNumber();
cout << "\n" ;
return 0;
}
|
Java
import java.util.HashMap;
class Node {
Node next;
Node prev;
int data;
Node( int data)
{
this .data = data;
this .next = null ;
this .prev = null ;
}
}
public class Main {
static Node head = null , tail = null ;
static HashMap<Integer, Integer> occurrences
= new HashMap<>();
static HashMap<Integer, Node> address = new HashMap<>();
static void insert( int value)
{
occurrences.put(
value, occurrences.getOrDefault(value, 0 ) + 1 );
if (occurrences.get(value) == 1
&& !address.containsKey(value)) {
Node temp = new Node(value);
address.put(value, temp);
if (head == null ) {
head = temp;
tail = temp;
}
else {
tail.next = temp;
temp.prev = tail;
tail = temp;
}
}
else if (occurrences.get(value) > 1
&& address.containsKey(value)) {
Node temp = address.get(value);
address.remove(value);
if (temp == head) {
head = head.next;
head.prev = null ;
}
else if (temp == tail) {
tail = tail.prev;
tail.next = null ;
}
else {
temp.next.prev = temp.prev;
temp.prev.next = temp.next;
}
}
}
static void findUniqueNumber()
{
if (head == null )
System.out.println( "-1" );
else
System.out.println(head.data);
}
public static void main(String[] args)
{
insert( 4 );
insert( 1 );
insert( 4 );
findUniqueNumber();
System.out.println();
}
}
|
Python3
class node:
def __init__( self ):
self . next = None
self .prev = None
self .data = 0
head = None
tail = None
occurrences = dict ()
address = dict ()
def insert(value):
global head, tail
if value not in occurrences:
occurrences[value] = 0
occurrences[value] + = 1
if (value in occurrences and
occurrences[value] = = 1 and
value not in address):
temp = node()
temp. next = None
temp.prev = None
temp.data = value
address[value] = temp
if (head = = None ):
head = temp
tail = temp
else :
tail. next = temp
temp.prev = tail
tail = temp
elif (value in occurrences and
occurrences[value] > 1 and
value in address):
temp = address[value]
address.pop(value)
if (temp = = head):
temp = head
head = head. next
del (temp)
elif (temp = = tail):
temp = tail
tail.prev. next = None
del (temp)
else :
temp. next .prev = temp.prev
temp.prev. next = temp. next
del (temp)
def findUniqueNumber():
global head
if (head = = None ):
print ( - 1 )
else :
print (head.data)
if __name__ = = '__main__' :
insert( 4 )
insert( 1 )
insert( 4 )
findUniqueNumber()
|
C#
using System;
using System.Collections.Generic;
class Node {
public Node next;
public Node prev;
public int data;
public Node( int data)
{
this .data = data;
this .next = null ;
this .prev = null ;
}
}
class MainClass {
static Node head = null , tail = null ;
static Dictionary< int , int > occurrences
= new Dictionary< int , int >();
static Dictionary< int , Node> address
= new Dictionary< int , Node>();
static void Insert( int value)
{
if (occurrences.ContainsKey(value)) {
occurrences[value]++;
}
else {
occurrences[value] = 1;
}
if (occurrences[value] == 1
&& !address.ContainsKey(value)) {
Node temp = new Node(value);
address[value] = temp;
if (head == null ) {
head = temp;
tail = temp;
}
else {
tail.next = temp;
temp.prev = tail;
tail = temp;
}
}
else if (occurrences[value] > 1
&& address.ContainsKey(value)) {
Node temp = address[value];
address.Remove(value);
if (temp == head) {
head = head.next;
head.prev = null ;
}
else if (temp == tail) {
tail = tail.prev;
tail.next = null ;
}
else {
temp.next.prev = temp.prev;
temp.prev.next = temp.next;
}
}
}
static void FindUniqueNumber()
{
if (head == null )
Console.WriteLine( "-1" );
else
Console.WriteLine(head.data);
}
public static void Main( string [] args)
{
Insert(4);
Insert(1);
Insert(4);
FindUniqueNumber();
Console.WriteLine();
}
}
|
Javascript
class Node {
constructor() {
this .next = null ;
this .prev = null ;
this .data = 0;
}
}
let head = null ;
let tail = null ;
const occurrences = new Map();
const address = new Map();
function insert(value) {
if (!occurrences.has(value)) {
occurrences.set(value, 0);
}
occurrences.set(value, occurrences.get(value) + 1);
if (
occurrences.has(value) &&
occurrences.get(value) === 1 &&
!address.has(value)
) {
const temp = new Node();
temp.next = null ;
temp.prev = null ;
temp.data = value;
address.set(value, temp);
if (head === null ) {
head = temp;
tail = temp;
} else {
tail.next = temp;
temp.prev = tail;
tail = temp;
}
}
else if (
occurrences.has(value) &&
occurrences.get(value) > 1 &&
address.has(value)
) {
const temp = address.get(value);
address. delete (value);
if (temp === head) {
head = head.next;
head.prev = null ;
temp.next = null ;
temp.prev = null ;
} else if (temp === tail) {
tail = tail.prev;
tail.next = null ;
temp.next = null ;
temp.prev = null ;
} else {
temp.prev.next = temp.next;
temp.next.prev = temp.prev;
temp.next = null ;
temp.prev = null ;
}
}
}
function findUniqueNumber() {
if (head === null ) {
console.log(-1);
} else {
console.log(head.data);
}
}
insert(4);
insert(1);
insert(4);
findUniqueNumber();
|
Time Complexity: O(1) for insertion and deletion operations
Auxiliary Space: O(n), where n is the number of unique elements
Share your thoughts in the comments
Please Login to comment...