程序员老鬼

年薪 300万大厂程序员被女友炫富害惨,原地失业。。

刚看到个贴子,说某大厂程序员年薪300万,结果因为女友炫富发朋友圈,什么转账4万、买大平层都晒出来,最后被前同事举报直接失业了。

Image

我觉得这事吧,本质不是炫不炫的问题,而是“你以为你在谈恋爱,别人却在记仇”。程序员有钱不是问题,问题是你高调到把自己暴露在风口浪尖,尤其是在信息不对等、利益冲突的职场里,你不知道谁在看、谁在算。

Image

网友们有的说“活该”,有的说“女友坑了他”,但说到底,还是职场心机战场,不懂低调就容易吃亏。

赚钱可以高调,做人一定得低调。尤其现在这年头,连朋友圈都成了战场。总的来说还是:财不外露,福不声张,低调一点,活得久一点。【备注:文末可领最新资料】

算法题:全 O(1) 的数据结构

要搞一个“全 O(1)”的结构,说实话,这题面试场上我也被问过,当时脑子一热就想直接上 HashMap,结果被面试官一个“那插入和删除还能 O(1) 吗?”给怼回来了 😂。后来回去一通补课,才真理解这玩意儿的精髓。

题目是这样的:你得实现一个支持以下操作的数据结构,且所有操作都必须是 O(1) 的:

  • inc(key):插入一个新 key,或者将现有 key 对应的计数加一。
  • dec(key):key 对应的计数减一;如果减到 0,就把 key 移除。
  • getMaxKey():返回任意一个计数最大的 key。
  • getMinKey():返回任意一个计数最小的 key。

当你听到 “全 O(1)” 四个字,其实就是在暗示你:得用 HashMap + 双向链表的组合拳。

核心思想就是搞两个东西:

  1. 用一个 Map<String, Node> 存每个 key 当前所在的计数节点;
  2. 每个 Node 是个双向链表节点,代表某个具体的 count 值,还挂着一堆 key(Set 存着);
  3. 整个链表按照 count 从小到大排好,头是 min,尾是 max。

这样你就能在 O(1) 时间内干这些事:

  • 插入 key:查 Map,找不到就插入 count=1 的节点(如果没有就新建),放进去;
  • 删除 key:count–,如果 count==0,干掉这个 key,否则转移到 count-1 的节点;
  • 找 max/min:直接链表的尾部和头部,轻轻松松。

听着有点抽象?贴个核心代码你就懂了:

classAllOne{

classNode{
int count;
        Set<String> keys = new HashSet<>();
        Node prev, next;
        Node(int c) { count = c; }
    }

private Map<String, Node> map = new HashMap<>();
private Node head = new Node(-1), tail = new Node(-1);

publicAllOne(){
        head.next = tail;
        tail.prev = head;
    }

publicvoidinc(String key){
        Node cur = map.get(key);
        Node newNode;

if (cur == null) {
if (head.next.count != 1) {
                newNode = new Node(1);
                insertAfter(head, newNode);
            } else newNode = head.next;
            newNode.keys.add(key);
            map.put(key, newNode);
        } else {
if (cur.next.count != cur.count + 1) {
                newNode = new Node(cur.count + 1);
                insertAfter(cur, newNode);
            } else newNode = cur.next;

            newNode.keys.add(key);
            cur.keys.remove(key);
if (cur.keys.isEmpty()) remove(cur);
            map.put(key, newNode);
        }
    }

publicvoiddec(String key){
        Node cur = map.get(key);
if (cur == null) return;

if (cur.count == 1) {
            cur.keys.remove(key);
            map.remove(key);
        } else {
            Node newNode;
if (cur.prev.count != cur.count - 1) {
                newNode = new Node(cur.count - 1);
                insertAfter(cur.prev, newNode);
            } else newNode = cur.prev;
            newNode.keys.add(key);
            map.put(key, newNode);
        }

        cur.keys.remove(key);
if (cur.keys.isEmpty()) remove(cur);
    }

public String getMaxKey(){
return tail.prev == head ? "" : tail.prev.keys.iterator().next();
    }

public String getMinKey(){
return head.next == tail ? "" : head.next.keys.iterator().next();
    }

privatevoidinsertAfter(Node prev, Node node){
        node.next = prev.next;
        node.prev = prev;
        prev.next.prev = node;
        prev.next = node;
    }

privatevoidremove(Node node){
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
}

讲真,这结构不光优雅,而且特别像你在大型项目中为了追求极致性能时的那种骚操作,什么 LRU 缓存、频率控制器、权限限流,都能学以致用。

但我还是要泼个冷水:现实中很少需要“所有操作都 O(1)”的结构,更多时候我们宁愿换个思路做空间换时间,或者干脆懒点全交给 Redis 🤷。

不过呢,面试爱考,系统设计题爱考,掌握了这招至少能证明:你不光会写代码,还能写骚代码 😎。

哪天你们碰上这种问题时,别慌,记得:HashMap + 双向链表,O(1) 就能拿下全场!💪

最后,我为大家打造了一份deepseek的入门到精通教程,完全免费:https://www.songshuhezi.com/deepseek

-END-

最后给大家分享一份不错的副业资料,感兴趣的同学可以链接我,微信:hls404 找我领取。