#1206

Design Skiplist

Hard
Linked ListDesignLinked ListRandomized Algorithms
LeetCode ↗

Approaches

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

Intuition

Time O(log n)Space O(n)

The optimal approach uses multiple layers of linked lists to create a Skiplist, allowing us to skip over many elements, which reduces the time complexity of search, add, and erase operations to O(log n). This is similar to how you might skip steps when climbing a staircase.

⚙️

Algorithm

4 steps
  1. 1Step 1: Create a Skiplist with multiple levels, where each level is a sorted linked list.
  2. 2Step 2: For search, start from the topmost level and move downwards, skipping nodes as necessary until you find the target or reach the bottom.
  3. 3Step 3: For add, randomly decide the level of the new node and insert it into each level accordingly.
  4. 4Step 4: For erase, locate the node in all levels and remove it.
solution.py53 lines
1# Full working Python code
2import random
3
4class Node:
5    def __init__(self, value, level):
6        self.value = value
7        self.forward = [None] * (level + 1)
8
9class Skiplist:
10    def __init__(self):
11        self.max_level = 16
12        self.header = Node(-1, self.max_level)
13        self.level = 0
14
15    def random_level(self):
16        level = 0
17        while random.random() < 0.5 and level < self.max_level:
18            level += 1
19        return level
20
21    def search(self, target):
22        current = self.header
23        for i in range(self.level, -1, -1):
24            while current.forward[i] and current.forward[i].value < target:
25                current = current.forward[i]
26        current = current.forward[0]
27        return current is not None and current.value == target
28
29    def add(self, num):
30        new_level = self.random_level()
31        if new_level > self.level:
32            for i in range(self.level + 1, new_level + 1):
33                self.header.forward[i] = None
34            self.level = new_level
35        new_node = Node(num, new_level)
36        current = self.header
37        for i in range(self.level, -1, -1):
38            while current.forward[i] and current.forward[i].value < num:
39                current = current.forward[i]
40            if i <= new_level:
41                new_node.forward[i] = current.forward[i]
42                current.forward[i] = new_node
43
44    def erase(self, num):
45        current = self.header
46        found = False
47        for i in range(self.level, -1, -1):
48            while current.forward[i] and current.forward[i].value < num:
49                current = current.forward[i]
50            if current.forward[i] and current.forward[i].value == num:
51                found = True
52                current.forward[i] = current.forward[i].forward[i]
53        return found

Complexity note: The time complexity is O(log n) because we can skip many nodes in each operation, effectively reducing the number of comparisons needed.

  • 1Skiplist allows for efficient search, add, and erase operations by using multiple layers.
  • 2Randomly determining the level of nodes helps maintain balance, similar to how trees balance themselves.

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