经典算法题

本文最后更新于 2 分钟前,文中所描述的信息可能已发生改变。

Data Structure

146. LRU 缓存机制

双向链表存储数据状态,哈希表更新数据。

python
class Node:

    def __init__(self, key=0, value=0):
        self.key = key
        self.value = value

class LRUCache:

    def __init__(self, capacity: int):
        self.capacity = capacity
        self.key_to_node = defaultdict(int)
        self.dummy = Node()
        self.dummy.prev = self.dummy
        self.dummy.next = self.dummy

    def get_node(self, key: int) -> Optional[Node]:
        if key not in self.key_to_node:
            return None
        node = self.key_to_node[key]
        self.remove(node)
        self.push_front(node)
        return node

    def get(self, key: int) -> int:
        node = self.get_node(key)
        return node.value if node else -1

    def put(self, key: int, value: int) -> None:
        node = self.get_node(key)
        if node:
            node.value = value
            return
        self.key_to_node[key] = node = Node(key, value)
        self.push_front(node)
        if len(self.key_to_node) > self.capacity:
            back_node = self.dummy.prev
            self.remove(back_node)
            del self.key_to_node[back_node.key]

    def remove(self, node: Node) -> None:
        node.prev.next = node.next
        node.next.prev = node.prev

    def push_front(self, node: Node) -> None:
        node.prev = self.dummy
        node.next = self.dummy.next
        node.prev.next = node
        node.next.prev = node

# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
java
class LRUCache {

    private static class Node {
        private int key, value;
        private Node prev, next;

        Node (int key, int value) {
            this.key = key;
            this.value = value;
        }
    }

    private final int capacity;
    private final Node dummy = new Node(0, 0);
    private final Map<Integer, Node> keyToNode = new HashMap<>();

    public LRUCache(int capacity) {
        this.capacity = capacity;
        dummy.prev = dummy;
        dummy.next = dummy;
    }

    public int get(int key) {
        Node node = getNode(key);
        return node != null ? node.value: -1;
    }

    public void put(int key, int value) {
        Node node = getNode(key);
        if (node != null) {
            node.value = value;
            return;
        }
        node = new Node(key, value);
        keyToNode.put(key, node);
        pushFirst(node);
        if (keyToNode.size() > capacity) {
            Node backNode = dummy.prev;
            keyToNode.remove(backNode.key);
            remove(backNode);
        }
    }

    private Node getNode(int key) {
        if (!keyToNode.containsKey(key)) {
            return null;
        }
        Node node = keyToNode.get(key);
        remove(node);
        pushFirst(node);
        return node;
    }

    private void remove(Node node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private void pushFirst(Node node) {
        node.prev = dummy;
        node.next = dummy.next;
        node.prev.next = node;
        node.next.prev = node;
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

460. LFU 缓存

双向链表存储数据状态,哈希表更新数据,不同频率的数据存储在不同的双向链表中。

python
class Node:

    def __init__(self, key=0, value=0):
        self.key = key
        self.value = value
        self.freq = 1

class LFUCache:

    def __init__(self, capacity: int):
        def new_list():
            dummy = Node()
            dummy.prev = dummy
            dummy.next = dummy
            return dummy
        self.capacity = capacity
        self.key_to_node = defaultdict(int)
        self.freq_to_dummy = defaultdict(new_list)

    def get_node(self, key: int) -> Optional[Node]:
        if key not in self.key_to_node:
            return None
        node = self.key_to_node[key]
        self.remove(node)
        dummy = self.freq_to_dummy[node.freq]
        if dummy.prev == dummy:
            del self.freq_to_dummy[node.freq]
            if self.min_freq == node.freq:
                self.min_freq += 1
        node.freq += 1
        self.push_front(self.freq_to_dummy[node.freq], node)
        return node

    def get(self, key: int) -> int:
        node = self.get_node(key)
        return node.value if node else -1

    def put(self, key: int, value: int) -> None:
        node = self.get_node(key)
        if node:
            node.value = value
            return
        if len(self.key_to_node) == self.capacity:
            dummy = self.freq_to_dummy[self.min_freq]
            back_node = dummy.prev
            del self.key_to_node[back_node.key]
            self.remove(back_node)
            if dummy.prev == dummy:
                del self.freq_to_dummy[self.min_freq]
        self.key_to_node[key] = node = Node(key, value)
        self.min_freq = 1
        self.push_front(self.freq_to_dummy[self.min_freq], node)

    def remove(self, node: Node) -> None:
        node.prev.next = node.next
        node.next.prev = node.prev

    def push_front(self, dummy: Node, node: Node) -> None:
        node.prev = dummy
        node.next = dummy.next
        node.prev.next = node
        node.next.prev = node

# Your LFUCache object will be instantiated and called as such:
# obj = LFUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
java
class LFUCache {

    private static class Node {
        private int key, value, freq = 1;
        private Node prev, next;

        Node (int key, int value) {
            this.key = key;
            this.value = value;
        }
    }

    private final int capacity;
    private final Map<Integer, Node> keyToNode = new HashMap<>();
    private final Map<Integer, Node> freqToDummy = new HashMap<>();
    private int minFreq;

    public LFUCache(int capacity) {
        this.capacity = capacity;
    }

    public int get(int key) {
        Node node = getNode(key);
        return node != null ? node.value: -1;
    }

    public void put(int key, int value) {
        Node node = getNode(key);
        if (node != null) {
            node.value = value;
            return;
        }
        if (keyToNode.size() == capacity) {
            Node dummy = freqToDummy.get(minFreq);
            Node backNode = dummy.prev;
            keyToNode.remove(backNode.key);
            remove(backNode);
            if (dummy.prev == dummy) {
                freqToDummy.remove(minFreq);
            }
        }
        node = new Node(key, value);
        keyToNode.put(key, node);
        minFreq = 1;
        pushFirst(minFreq, node);
    }

    private Node getNode(int key) {
        if (!keyToNode.containsKey(key)) {
            return null;
        }
        Node node = keyToNode.get(key);
        remove(node);
        Node dummy = freqToDummy.get(node.freq);
        if (dummy.prev == dummy) {
            freqToDummy.remove(node.freq);
            if (minFreq == node.freq) {
                minFreq++;
            }
        }
        pushFirst(++node.freq, node);
        return node;
    }

    private Node newList() {
        Node dummy = new Node(0, 0);
        dummy.prev = dummy;
        dummy.next = dummy;
        return dummy;
    }

    private void remove(Node node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private void pushFirst(int freq, Node node) {
        Node dummy = freqToDummy.computeIfAbsent(freq, k -> newList());
        node.prev = dummy;
        node.next = dummy.next;
        node.prev.next = node;
        node.next.prev = node;
    }

}

/**
 * Your LFUCache object will be instantiated and called as such:
 * LFUCache obj = new LFUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

1206. 设计跳表

python
class SkiplistNode():

    def __init__(self, val: int, max_level=32):
        self.val = val
        self.forward = [None] * max_level

class Skiplist:

    max_level = 32
    p_factor = 0.5

    def __init__(self):
        self.head = SkiplistNode(-1)
        self.level = 0

    def random_level(self):
        level = 1
        while level < self.max_level and random.random() < self.p_factor:
            level += 1
        return level

    def search(self, target: int) -> bool:
        cur = self.head
        for i in range(self.level - 1, -1, -1):
            while cur.forward[i] and cur.forward[i].val < target:
                cur = cur.forward[i]
        cur = cur.forward[0]
        return cur is not None and cur.val == target

    def add(self, num: int) -> None:
        update = [self.head] * self.max_level
        cur = self.head
        for i in range(self.level - 1, -1, -1):
            while cur.forward[i] and cur.forward[i].val < num:
                cur = cur.forward[i]
            update[i] = cur

        level = self.random_level()
        self.level = max(self.level, level)
        node = SkiplistNode(num, level)

        for i in range(level):
            node.forward[i] = update[i].forward[i]
            update[i].forward[i] = node


    def erase(self, num: int) -> bool:
        update = [None] * self.max_level
        cur = self.head
        for i in range(self.level - 1, -1, -1):
            while cur.forward[i] and cur.forward[i].val < num:
                cur = cur.forward[i]
            update[i] = cur
        cur = cur.forward[0]

        if cur is None or cur.val != num:
            return False

        for i in range(self.level):
            if update[i].forward[i] != cur:
                break
            update[i].forward[i] = cur.forward[i]

        while self.level > 1 and self.head.forward[self.level - 1] is None:
            self.level -= 1
        return True


# Your Skiplist object will be instantiated and called as such:
# obj = Skiplist()
# param_1 = obj.search(target)
# obj.add(num)
# param_3 = obj.erase(num)
java
class SkiplistNode {

    int val;
    SkiplistNode[] forward;

    public SkiplistNode(int val, int maxLevel) {
        this.val = val;
        this.forward = new SkiplistNode[maxLevel];
    }

}

class Skiplist {

    int level = 0;
    int maxLevel = 32;
    SkiplistNode head = new SkiplistNode(-1, maxLevel);

    private int randomLevel() {
        int lv = 1;
        Random random = new Random();
        while (lv < maxLevel && random.nextInt(2) == 0) {
            lv++;
        }
        return lv;
    }

    public boolean search(int target) {
        SkiplistNode cur = head;
        for (int i = level - 1; i >= 0; i--) {
            while (cur.forward[i] != null && cur.forward[i].val < target) {
                cur = cur.forward[i];
            }
        }
        cur = cur.forward[0];
        return cur != null && cur.val == target;
    }

    public void add(int num) {
        SkiplistNode[] update = new SkiplistNode[maxLevel];
        SkiplistNode cur = head;
        for (int i = level - 1; i >= 0; i--) {
            while (cur.forward[i] != null && cur.forward[i].val < num) {
                cur = cur.forward[i];
            }
            update[i] = cur;
        }

        int lv = randomLevel();
        if (lv > level) {
            for (int i = level; i < lv; i++) {
                update[i] = head;
            }
            level = lv;
        }

        SkiplistNode node = new SkiplistNode(num, lv);
        for (int i = 0; i < lv; i++) {
            node.forward[i] = update[i].forward[i];
            update[i].forward[i] = node;
        }
    }

    public boolean erase(int num) {
        SkiplistNode[] update = new SkiplistNode[maxLevel];
        SkiplistNode cur = head;
        for (int i = level - 1; i >= 0; i--) {
            while (cur.forward[i] != null && cur.forward[i].val < num) {
                cur = cur.forward[i];
            }
            update[i] = cur;
        }
        cur = cur.forward[0];

        if (cur == null || cur.val != num) {
            return false;
        }

        for (int i = 0; i < level && update[i].forward[i] == cur; i++) {
            update[i].forward[i] = cur.forward[i];
        }

        while (level > 0 && head.forward[level - 1] == null) {
            level--;
        }
        return true;
    }
}

/**
 * Your Skiplist object will be instantiated and called as such:
 * Skiplist obj = new Skiplist();
 * boolean param_1 = obj.search(target);
 * obj.add(num);
 * boolean param_3 = obj.erase(num);
 */
Common Resources for Materials Calculation