请记住,从你被打低绩效开始那一刻,你就已经不是团队的牛马,更不是嫡系,而是未来随时可以牺牲的耗材。
刚看到个贴子,大意是:一旦被打低绩效,你就不再是自己人,只是随时可丢的耗材,所以别讲责任、别讲大局观,干脆躺平摆烂、摸鱼到底。
情绪我懂,但结论真挺害人。被打低绩效,说明的是你在这个团队的处境危险,不等于你在整个职场都废了。把责任心和善良都扔了,看似解气,其实是把自己从“备胎”变成“废胎”。
网友们说“躺平是最明智的选择”,我只部分认同——该保护自己就保护,比如别再傻乎乎加班、别无底线付出,这是“止损”;但真正的底层逻辑应该是:一边看清现实,降低期待,一边悄悄练好本事,提升谈条件的底气。
换个角度想,被打低绩效也许是信号:是时候思考要不要换团队、换赛道,而不是把自己按在泥里不再爬
面试题:最小覆盖子串
昨天晚上十一点多吧,我在公司楼下抽烟,手机还在震,群里有人又发“哥,线上日志里那个 traceId 关键字怎么老是匹配一大坨,能不能只拿到最短那段”。我当时脑子里第一反应不是查 ES,是突然想到算法题那个“最小覆盖子串”,就很像:你要在一整条字符串里,找一段最短的窗口,刚好把你关心的那些字符都“覆盖”住,少一个都不行,多了还嫌长…嗯就这味儿。
我说个更生活的版本哈:S 是一整行日志拼出来的长串,T 是你必须命中的那些 token(比如 “ERROR”“Broken pipe”“timeout” 这种),你要的就是最短那段日志片段,能把 T 里所有字符都凑齐。你要是暴力扫,基本就跟我当年写 for 三层一样,风扇起飞,CPU 冒烟,最后还被同事骂“你这不就是拿线上当压测么”。
所以就得用滑动窗口。说白了就是俩指针 l、r,右指针一路扩,扩到“够了”为止;够了就左指针收缩,能收多短收多短,边收边更新答案。关键点在“够了”怎么判断:用两个计数表,一个是 need(T 里每个字符要几个),一个是 window(当前窗口里有几个)。然后再搞个 formed,表示当前窗口里有多少种字符已经满足 need 的数量要求。formed == required 的时候,窗口就“覆盖了”,可以收缩。
我直接把 Java 代码贴这儿,都是我自己平时刷题那套写法,比较偏工程风格,变量名我尽量写得像人话一点,免得你们看着烦:
import java.util.HashMap;
import java.util.Map;
publicclassMinWindowSubstring{
publicstatic String minWindow(String s, String t){
if (s == null || t == null || t.length() == 0 || s.length() < t.length()) return"";
Map<Character, Integer> need = new HashMap<>();
for (int i = 0; i < t.length(); i++) {
char c = t.charAt(i);
need.put(c, need.getOrDefault(c, 0) + 1);
}
int required = need.size();
int formed = 0;
Map<Character, Integer> window = new HashMap<>();
int l = 0, r = 0;
int bestLen = Integer.MAX_VALUE;
int bestL = 0;
while (r < s.length()) {
char c = s.charAt(r);
window.put(c, window.getOrDefault(c, 0) + 1);
if (need.containsKey(c) && window.get(c).intValue() == need.get(c).intValue()) {
formed++;
}
while (l <= r && formed == required) {
// 更新最优解
int len = r - l + 1;
if (len < bestLen) {
bestLen = len;
bestL = l;
}
// 尝试收缩左边界
char leftChar = s.charAt(l);
window.put(leftChar, window.get(leftChar) - 1);
if (need.containsKey(leftChar) && window.get(leftChar).intValue() < need.get(leftChar).intValue()) {
formed--;
}
l++;
}
r++;
}
return bestLen == Integer.MAX_VALUE ? "" : s.substring(bestL, bestL + bestLen);
}
// 小自测
publicstaticvoidmain(String[] args){
System.out.println(minWindow("ADOBECODEBANC", "ABC")); // BANC
System.out.println(minWindow("a", "a")); // a
System.out.println(minWindow("a", "aa")); // ""
}
}
你们注意哈,这题最容易写崩的地方不是思路,是细节: 一个是 formed 的增减必须卡在“刚好等于 need”那一刻,不然你窗口里字符多了也会乱加;另一个是收缩的时候,左边字符减完如果跌破 need,formed 要立刻减回去,不然你会以为窗口还覆盖着,结果答案缩过头了。
还有个小插曲,我之前写故障排查那类东西(就那种“看日志像法医找痕迹”的感觉),其实跟这个窗口收缩特别像:先把范围扩大到能复现,再一点点把无关变量剔掉,最后剩下那个最短路径就是根因…嗯扯远了,反正算法和排查真挺像的。
行了我先不说了,刚又有人@我问“为啥我这个 HashMap 用 int[] 会不会更快”,我得去回两句,不然他们又要拿我当性能背锅侠了…