All O`one Data Structure

HardHash TableLinked ListDesignDoubly-Linked List

Solution

export class AllOne {
  private readonly head: Node;
  private readonly tail: Node;
  private readonly map: Map<string, Node>;
 
  constructor() {
    this.head = new Node(0);
    this.tail = new Node(0);
    this.head.next = this.tail;
    this.tail.prev = this.head;
    this.map = new Map();
  }
 
  inc(key: string): void {
    const node = this.map.get(key);
    if (node) {
      node.keys.delete(key);
      const freq = node.freq;
      const nextNode = node.next;
      if (nextNode && (nextNode === this.tail || nextNode.freq !== freq + 1)) {
        const newNode = new Node(freq + 1);
        newNode.keys.add(key);
        newNode.prev = node;
        newNode.next = nextNode;
        node.next = newNode;
        nextNode.prev = newNode;
        this.map.set(key, newNode);
      } else if (nextNode) {
        nextNode.keys.add(key);
        this.map.set(key, nextNode);
      }
 
      if (node.keys.size === 0) {
        this.removeNode(node);
      }
    } else {
      const firstNode = this.head.next;
      if (firstNode && (firstNode === this.tail || 1 < firstNode.freq)) {
        const newNode = new Node(1);
        newNode.keys.add(key);
        newNode.prev = this.head;
        newNode.next = firstNode;
        this.head.next = newNode;
        firstNode.prev = newNode;
        this.map.set(key, newNode);
      } else if (firstNode) {
        firstNode.keys.add(key);
        this.map.set(key, firstNode);
      }
    }
  }
 
  dec(key: string): void {
    const node = this.map.get(key);
    if (!node) {
      return;
    }
    node.keys.delete(key);
    const freq = node.freq;
 
    if (freq === 1) {
      this.map.delete(key);
    } else {
      const prevNode = node.prev;
      if (prevNode && (prevNode === this.head || prevNode.freq !== freq - 1)) {
        const newNode = new Node(freq - 1);
        newNode.keys.add(key);
        newNode.prev = prevNode;
        newNode.next = node;
        prevNode.next = newNode;
        node.prev = newNode;
        this.map.set(key, newNode);
      } else if (prevNode) {
        prevNode.keys.add(key);
        this.map.set(key, prevNode);
      }
    }
 
    if (node.keys.size === 0) {
      this.removeNode(node);
    }
  }
 
  getMaxKey(): string {
    if (!this.tail.prev || this.tail.prev === this.head) {
      return '';
    }
    return this.tail.prev.keys.values().next().value;
  }
 
  getMinKey(): string {
    if (!this.head.next || this.head.next === this.tail) {
      return '';
    }
    return this.head.next.keys.values().next().value;
  }
 
  removeNode(node: Node): void {
    const prevNode = node.prev;
    const nextNode = node.next;
    if (prevNode) {
      prevNode.next = nextNode;
    }
    if (nextNode) {
      nextNode.prev = prevNode;
    }
  }
}
 
class Node {
  public freq: number;
  public prev: Node | null;
  public next: Node | null;
  public readonly keys: Set<string>;
 
  constructor(freq: number) {
    this.freq = freq;
    this.prev = null;
    this.next = null;
    this.keys = new Set();
  }
}

Complexity

  • Time: O(1)
  • Space: O(N)