返回

设计模式大师课:揭秘 LeetCode 中的缓存与栈

后端

在软件开发领域,设计模式是一套经过验证的解决方案,用于解决常见的设计问题。它们提供了可重用且可靠的蓝图,使开发人员能够创建灵活、可维护和可扩展的应用程序。在本文中,我们将深入探讨两种流行的设计模式:缓存和栈,并通过 LeetCode 中的实际问题来演示其应用。

1. 缓存(LRU)

问题: LeetCode 146. LRU 缓存

**** 设计一个缓存系统,其中最近使用的数据总是保留,而最久未使用的则会被删除。

解决方案:
缓存: 缓存是一种临时存储,用于在短期内快速访问数据。它通过将最近使用的数据保留在内存中,从而减少对慢速存储器(例如数据库)的访问。

LRU(最近最少使用)算法: LRU 算法是一种淘汰策略,它跟踪数据访问的顺序,并将最久未使用的项逐出缓存。

Java 实现:

public class LRUCache {
    private Map<Integer, Node> cache;
    private int capacity;
    private Node head, tail;

    public LRUCache(int capacity) {
        this.cache = new HashMap<>();
        this.capacity = capacity;
        this.head = new Node();
        this.tail = new Node();
        head.next = tail;
        tail.prev = head;
    }

    public int get(int key) {
        Node node = cache.get(key);
        if (node == null) {
            return -1;
        }
        remove(node);
        insertAtHead(node);
        return node.value;
    }

    public void put(int key, int value) {
        Node node = cache.get(key);
        if (node == null) {
            node = new Node(key, value);
            cache.put(key, node);
            insertAtHead(node);
        } else {
            node.value = value;
            remove(node);
            insertAtHead(node);
        }

        if (cache.size() > capacity) {
            removeTail();
        }
    }

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

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

    private void removeTail() {
        Node node = tail.prev;
        remove(node);
        cache.remove(node.key);
    }

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

        public Node() {}

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

2. 栈

问题: LeetCode 155. 最小栈

设计一个栈,除了正常的栈操作之外,还支持在任何时刻获取栈中的最小值。

解决方案:
栈: 栈是一种线性数据结构,遵循后进先出的原则。

辅助栈: 为了在恒定的时间复杂度内获取最小值,我们可以使用一个辅助栈来跟踪每个插入栈中的最小值。辅助栈始终保存到当前为止遇到的最小值。

Java 实现:

public class MinStack {
    private Stack<Integer> stack;
    private Stack<Integer> minStack;

    public MinStack() {
        stack = new Stack<>();
        minStack = new Stack<>();
    }

    public void push(int x) {
        stack.push(x);
        if (minStack.isEmpty() || x <= minStack.peek()) {
            minStack.push(x);
        }
    }

    public int pop() {
        int x = stack.pop();
        if (x == minStack.peek()) {
            minStack.pop();
        }
        return x;
    }

    public int top() {
        return stack.peek();
    }

    public int getMin() {
        return minStack.peek();
    }
}

结论

缓存和栈是广泛使用且功能强大的设计模式,对于优化应用程序性能至关重要。通过了解和应用这些模式,开发人员可以创建高效、可靠和可扩展的解决方案。LeetCode 中的示例问题为这些模式的实际应用提供了丰富的素材。深入理解这些模式将使您在软件开发职业生涯中获得巨大的优势。

附录