我妹国企的工资,看完一点都不羡慕了
国企这滤镜,真该碎一碎了。 网友晒妹妹工资条,实发1930,评论区一堆人先是愣住,接着开始自我安慰:这点钱,在大城市连像样点的房租都扛不住,还谈什么“稳定体面”。也有人说,国企看的是长线,五险一金、假期、食堂、福利,不能只盯着到手那点。
但话说回来,到手1930这事,真不是“别只看眼前”就能糊弄过去的。工资低成这样,连基本生活都得精打细算,稳定听着像优点,落到本人头上,可能就是不敢辞职,也不敢生病。很多人羡慕国企,其实羡慕的是想象里的国企,不是这种月底一看余额心口发紧的版本。
说难听点,1930的“稳定”,更像把人稳定在不太敢折腾的状态里。HR看完估计都得装作没看见,这数字发出来,滤镜确实掉一地。
面试题:倒水
两个桶摆在那儿,一个 5 升,一个 3 升,目标是倒出 4 升。题看着像小学奥数,真写代码时,很多人第一反应还是一通模拟:装满、倒空、互相倒,分支越写越乱,最后自己都不敢改。
这种题我一般不先盯着“怎么倒”,先盯“状态”。 因为倒水过程本质上不是动作问题,是状态转移问题。你手上真正关心的,只有两个数:a 桶里还剩多少水,b 桶里还剩多少水。只要状态能表达清楚,后面就顺了。
比如 (0,0) 表示两个桶都空,(5,0) 表示 5 升桶满了,3 升桶空着,(2,3) 表示 5 升桶还有 2 升,3 升桶装满。 那从一个状态出发,能做的事情其实就 6 种:
装满 A 装满 B 倒空 A 倒空 B A 往 B 倒 B 往 A 倒
到这题就别再硬模拟步骤了,直接上 BFS。原因也很现实: 题目通常不光要你判断“能不能倒出来”,还经常顺手问“最少几步”。最短步数,BFS 天然合适。
Java 我会这样写,代码不长,但味道要对,核心是“状态去重 + 六种转移”。
import java.util.*;
publicclassWaterJug{
staticclassState{
int a;
int b;
int step;
State(int a, int b, int step) {
this.a = a;
this.b = b;
this.step = step;
}
}
publicstaticintminSteps(int capA, int capB, int target){
Queue<State> queue = new LinkedList<>();
boolean[][] visited = newboolean[capA + 1][capB + 1];
queue.offer(new State(0, 0, 0));
visited[0][0] = true;
while (!queue.isEmpty()) {
State cur = queue.poll();
if (cur.a == target || cur.b == target || cur.a + cur.b == target) {
return cur.step;
}
List<State> nextList = nextStates(cur, capA, capB);
for (State next : nextList) {
if (!visited[next.a][next.b]) {
visited[next.a][next.b] = true;
queue.offer(next);
}
}
}
return -1;
}
privatestatic List<State> nextStates(State s, int capA, int capB){
List<State> list = new ArrayList<>();
list.add(new State(capA, s.b, s.step + 1)); // 装满A
list.add(new State(s.a, capB, s.step + 1)); // 装满B
list.add(new State(0, s.b, s.step + 1)); // 倒空A
list.add(new State(s.a, 0, s.step + 1)); // 倒空B
int moveAtoB = Math.min(s.a, capB - s.b);
list.add(new State(s.a - moveAtoB, s.b + moveAtoB, s.step + 1));
int moveBtoA = Math.min(s.b, capA - s.a);
list.add(new State(s.a + moveBtoA, s.b - moveBtoA, s.step + 1));
return list;
}
publicstaticvoidmain(String[] args){
System.out.println(minSteps(5, 3, 4)); // 6
}
}
这段代码里,最容易写错的不是 BFS,本身就那点东西;真正容易翻车的是“倒水”这一步。 比如 A 往 B 倒,不是简单做 a--、b++,也不是一口气全倒完,而是只能倒到两种边界之一:
要么 A 倒空。 要么 B 装满。
所以才有这句:
int moveAtoB = Math.min(s.a, capB - s.b);
这地方我第一眼就会盯住,因为很多人代码能跑,但状态转移是歪的,样例一多马上露馅。
再往前走一步,其实这题还有个更省的判断: 如果目标值 target 大于两个桶容量之和,那肯定不可能。 再狠一点,若 target 不是 gcd(capA, capB) 的倍数,也不可能倒出来。这个是数学结论,能先剪掉不少无效情况。
if (target > capA + capB) return -1;
if (target % gcd(capA, capB) != 0) return -1;
算法题里,“倒水”不算难,难的是别把自己写进细节泥潭里。 动作看着很多,状态其实很少。把状态抽出来,剩下就是标准图搜索。很多题都一个路数:表面在演过程,骨子里在跑状态机。