#432

All O`one Data Structure

Hard
Hash TableLinked ListDesignDoubly-Linked ListHash MapDoubly Linked List
LeetCode ↗

Approaches

Brute ForceOptimal
Complexity Comparison
Brute ForceOptimal Solution
Time
O(n²)
O(1)
Space
O(n)
O(n)
💡

Intuition

Time O(1)Space O(n)

This approach uses a combination of a hash map and a doubly linked list to maintain the counts efficiently. The linked list allows for quick access to the minimum and maximum counts while the hash map keeps track of the keys and their corresponding nodes in the list.

⚙️

Algorithm

3 steps
  1. 1Step 1: Create a doubly linked list to maintain nodes representing counts.
  2. 2Step 2: Use a hash map to map each string to its count and the corresponding node in the linked list.
  3. 3Step 3: For increment and decrement operations, update the count and adjust the linked list accordingly to maintain order.
solution.py54 lines
1class Node:
2    def __init__(self, count):
3        self.count = count
4        self.keys = set()
5        self.prev = None
6        self.next = None
7
8class AllOne:
9    def __init__(self):
10        self.key_count = {}
11        self.head = Node(float('-inf'))
12        self.tail = Node(float('inf'))
13        self.head.next = self.tail
14        self.tail.prev = self.head
15
16    def _add_node(self, new_node, prev_node):
17        new_node.prev = prev_node
18        new_node.next = prev_node.next
19        prev_node.next.prev = new_node
20        prev_node.next = new_node
21
22    def _remove_node(self, node):
23        node.prev.next = node.next
24        node.next.prev = node.prev
25
26    def inc(self, key: str) -> None:
27        count = self.key_count.get(key, 0)
28        self.key_count[key] = count + 1
29        if count:
30            self._remove_node(self.key_count[key])
31        new_count = count + 1
32        if new_count not in self.key_count:
33            new_node = Node(new_count)
34            self._add_node(new_node, self.head)
35        self.head.next.keys.add(key)
36
37    def dec(self, key: str) -> None:
38        count = self.key_count[key]
39        self._remove_node(self.key_count[key])
40        if count == 1:
41            del self.key_count[key]
42        else:
43            self.key_count[key] = count - 1
44            new_count = count - 1
45            if new_count not in self.key_count:
46                new_node = Node(new_count)
47                self._add_node(new_node, self.head)
48            self.head.next.keys.add(key)
49
50    def getMaxKey(self) -> str:
51        return "" if self.head.next == self.tail else next(iter(self.head.next.keys))
52
53    def getMinKey(self) -> str:
54        return "" if self.tail.prev == self.head else next(iter(self.tail.prev.keys))

Complexity note: The time complexity is O(1) for all operations because we use a hash map for key counts and a linked list for maintaining order, allowing for constant time access to max and min keys.

  • 1Using a linked list allows for efficient insertions and deletions while maintaining order.
  • 2A hash map provides O(1) access to the count of each key, which is crucial for performance.

Solutions and explanations are original Tejav content. Problem titles © LeetCode — use the LeetCode button above for the full problem statement.