卷王的存在导致团队成员不敢按时下班,作为leader,怎么打破这种局面?
最近刷到一篇帖子,有点意思:有网友吐槽团队里出了个“卷王”,每天加班到飞起,搞得整个组都不敢按时下班。作为leader,该怎么打破这个局面?
评论区有个回答我差点笑出声:“你先走,就没人不下班了。”
我觉得这个说法其实挺有道理的。我们程序员都懂,加班文化要真从一个“卷王”开始蔓延,最后变成谁走谁尴尬,谁走谁被打标签“摸鱼仔”。
但问题是,如果leader自己天天坐在那儿不动,那其他人哪敢先走?这不是一个技术问题,是氛围问题,是默认KPI是熬夜的暗示。
我带过团队,我的方式就是:到点我先收电脑,站起来大声说一句“散了啊兄弟们,今天够了,回去吃饭去”。大家就会开始安心收拾东西,逐渐团队就养成了“按时下班是常态”的文化。
技术要内卷可以理解,但时间不能无限透支,没人能靠压榨工时变超人。再说了,代码写多了,bug也会跟着多啊。【备注:文末可领最新资料】
算法题:贴纸拼词
局长
“贴纸拼词”这道题,乍一看像是小学生玩的剪贴画,但你仔细一想,这分明是算法面试经典老炮题之一啊。题目是这样的:
给你一个字符串数组 stickers,每个字符串代表一个贴纸上的字母组合,还有一个目标字符串 target。你可以无限次使用这些贴纸(每次用一个贴纸上的一个字母),问最少需要多少个贴纸才能拼出目标字符串。
⚠️注意了:贴纸不能剪开来随便用,每次用就整张贴纸上去。
我第一次看到这题的时候,脑袋里浮现的是小学语文课那种“请用下面的字组成一个词”——嗯,果然是现代简约风格的背包问题。不过这题的坑点多得离谱,暴力 DFS 一踩就炸,面试的时候还不能暴露出你的 StackOverflow 灵魂,要优雅地递归,要高效地剪枝,最好还要记忆化搜索,来个 memo,面试官看到你这套组合拳,眼神就不一样了。
先说个最暴力但最出事的写法:
publicintminStickers(String[] stickers, String target) {
return dfs(stickers, target);
}
privateintdfs(String[] stickers, String target) {
if (target.length() == 0) return0;
intres= Integer.MAX_VALUE;
for (String sticker : stickers) {
StringBuildersb=newStringBuilder();
int[] cnt = newint[26];
for (char c : sticker.toCharArray()) cnt[c - 'a']++;
for (char c : target.toCharArray()) {
if (cnt[c - 'a'] > 0) cnt[c - 'a']--;
else sb.append(c);
}
if (sb.length() < target.length()) {
inttmp= dfs(stickers, sb.toString());
if (tmp != -1) res = Math.min(res, tmp + 1);
}
}
return res == Integer.MAX_VALUE ? -1 : res;
}这代码的问题在哪?你以为你在递归,其实你在搞自杀式调用。状态太多,重复计算,迟早 TLE(超时)。而且 target 一变化,重复子问题就像 Java 堆里的幽灵,一直飘在那儿。
所以我们需要 记忆化搜索,来加快速度。用一个 Map<String, Integer> 记录之前算过的 target 子问题的结果,避免重复。
不过,程序员进阶的标志就是学会用“位图 + 哈希优化 + 剪枝”这三板斧。
最好的做法是——用字符频次数组代替字符串本身。我们预处理每张贴纸的频率数组,然后递归时看哪个贴纸对当前 target 最有“打击面”(优先选择能贡献最多字母的贴纸),来做减法。
代码精简之后,看着也没那么费脑子:
publicint minStickers(String[] stickers, String target) {
int n= stickers.length;
int[][] stickerCounts = new int[n][26];
for (int i=0; i < n; i++) {
for (char c : stickers[i].toCharArray()) {
stickerCounts[i][c - 'a']++;
}
}
Map<String, Integer> memo = new HashMap<>();
memo.put("", 0);
return helper(stickerCounts, target, memo);
}
privateint helper(int[][] stickers, String target, Map<String, Integer> memo) {
if (memo.containsKey(target)) return memo.get(target);
int[] targetCount = new int[26];
for (char c : target.toCharArray()) targetCount[c - 'a']++;
int res = Integer.MAX_VALUE;
for (int[] sticker : stickers) {
// 贴纸中是否含有目标字符串的第一个字母
if (sticker[target.charAt(0) - 'a'] == 0) continue;
StringBuilder sb = new StringBuilder();
for (int i=0; i < 26; i++) {
if (targetCount[i] > 0) {
int remain = targetCount[i] - sticker[i];
for (int j=0; j < Math.max(0, remain); j++) {
sb.append((char) ('a' + i));
}
}
}
String newTarget= sb.toString();
int tmp= helper(stickers, newTarget, memo);
if (tmp != -1) res = Math.min(res, tmp + 1);
}
memo.put(target, res == Integer.MAX_VALUE ? -1 : res);
return memo.get(target);
}这段代码的关键就在于优化剪枝的策略和使用 memo 避免重复子问题。
说实话,这题就像你在面试现场看到的那种高级算法题,看起来平平无奇,实则“杀机四伏”。一不留神写出个全排列爆栈程序,面试官面不改色心里疯狂打。
我觉得真正解这种题的诀窍在于:不要死磕暴力法,哪怕你脑子能转,机器不能陪你转太久。面试讲究的不光是能不能做出来,还得让对方看出来你在压复杂度、懂数据结构、有优化思路。
对,我上次就看到一个候选人,直接上 DFS,target 每次 substring 剪出来接着跑,长得我头皮发麻。我问他优化点在哪,他说 Java 运行得快。好家伙,差点给我 CPU 烧了。
所以说,代码写得帅不帅不重要,得跑得快,跑得久,还不能炸。
写完我才想起这题其实和程序员点外卖也挺像的:你有一堆店铺(贴纸),菜单都差不多,但你要拼出一个你想吃的套餐(target)。你可以反复点,但你不能单点某个字母——只能整张菜单来。你点得越少,省钱越多。
希望你们在刷题的时候别像我一样——一开始用的暴力法,把自己暴力超时了
程序员朋友们,这题建议都练一练,哪天面试官点名来了,你还能笑着写完再抖个包袱,说句“这题我有原版”。
最后,我为大家打造了一份deepseek的入门到精通教程,完全免费:https://www.songshuhezi.com/deepseek
也可以看我写的这篇文章《DeepSeek满血复活,直接起飞!》来进行本地搭建。
-END-
以上,就是今天的分享了,看完文章记得右下角点赞,也欢迎在评论区写下你的留言。