年薪 300万大厂程序员被女友炫富害惨,原地失业。。
刚看到个贴子,说某大厂程序员年薪300万,结果因为女友炫富发朋友圈,什么转账4万、买大平层都晒出来,最后被前同事举报直接失业了。
我觉得这事吧,本质不是炫不炫的问题,而是“你以为你在谈恋爱,别人却在记仇”。程序员有钱不是问题,问题是你高调到把自己暴露在风口浪尖,尤其是在信息不对等、利益冲突的职场里,你不知道谁在看、谁在算。
网友们有的说“活该”,有的说“女友坑了他”,但说到底,还是职场心机战场,不懂低调就容易吃亏。
赚钱可以高调,做人一定得低调。尤其现在这年头,连朋友圈都成了战场。总的来说还是:财不外露,福不声张,低调一点,活得久一点。【备注:文末可领最新资料】
算法题:全 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 + 双向链表的组合拳。
核心思想就是搞两个东西:
用一个 Map<String, Node>存每个 key 当前所在的计数节点;每个 Node 是个双向链表节点,代表某个具体的 count 值,还挂着一堆 key(Set 存着); 整个链表按照 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-