程序员老鬼

朋友之前在腾讯做程序员,年薪 80万,去年 34岁考上了老家的事业编,在教育局工作,每个月工资6000块。他爸妈现在逢人就夸自己儿子有出息

朋友以前在大厂写代码,一年拿八十来万,放哪儿都算混得不错吧。结果去年三十多岁回老家考了个事业编,去了教育局,工资一下变成每月六千。

更好笑的是,他爸妈态度直接大反转。

以前儿子在腾讯上班,赚得多,他们也觉得脸上有光。现在不一样了,逢人就说儿子有出息了,进体制了,工作稳,说出去也体面,以后养老都不用愁。

Image

你说钱重要吧,八十万摆在那儿。你说面子重要吧,在老一辈眼里,编制两个字好像自带光环,工资少点都不算事。

只能说,大厂光环再亮,在县城亲戚饭桌上,可能真不如一句“在教育局上班”。

面试题:喧闹和富有

richer[i] = [a, b] 这种输入,第一眼别急着把它当普通排序题。

它说的是:a 比 b 有钱。

但题目要问的是:对每个人 x,在所有“比他有钱的人 + 他自己”里面,谁最安静。

这地方我一般不会先想怎么排序财富。财富大小其实没给具体数值,只给了关系。你手里拿到的不是数组,是一张有向图。

比如:

richer = [[1,0],[2,1],[3,1]]
quiet  = [5,3,8,1]

1 -> 0 表示 1 比 0 富有。

如果站在 0 的角度看,0 能往上找到 1,1 又能往上找到 2、3。

所以 0 的候选人其实是:

0, 1, 2, 3

再从 quiet 里面找最小值,答案就是 3。

这里最容易写别扭的地方,是建图方向。

我建议这样建:

poor -> rich

也就是如果 a 比 b 富有,就让 b 指向 a。

因为题目问的是“谁比我富有”,从当前人出发,一路往上找就行。

代码不要写成每个人都暴力扫一遍 richer。那样数据稍微大一点,就变成重复爬楼。比如 0 查过 1 的答案,后面再查 2、3 时又重新查,没必要。

这题用 DFS + 记忆化就很顺。

每个人的答案算一次,后面直接拿缓存。

Java 代码如下:

import java.util.*;

classSolution{

private List<Integer>[] richerGraph;
privateint[] quiet;
privateint[] best;

publicint[] loudAndRich(int[][] richer, int[] quiet) {
int n = quiet.length;
this.quiet = quiet;
this.best = newint[n];
        Arrays.fill(best, -1);

        richerGraph = new ArrayList[n];
for (int i = 0; i < n; i++) {
            richerGraph[i] = new ArrayList<>();
        }

for (int[] edge : richer) {
int rich = edge[0];
int poor = edge[1];
            richerGraph[poor].add(rich);
        }

int[] ans = newint[n];
for (int person = 0; person < n; person++) {
            ans[person] = findQuietest(person);
        }

return ans;
    }

privateintfindQuietest(int person){
if (best[person] != -1) {
return best[person];
        }

int candidate = person;

for (int rich : richerGraph[person]) {
int richBest = findQuietest(rich);
if (quiet[richBest] < quiet[candidate]) {
                candidate = richBest;
            }
        }

        best[person] = candidate;
return candidate;
    }
}

这里 findQuietest(person) 的含义很清楚:从 person 出发,沿着“比他富有”的边一直往上找,返回这批人里最安静的那个编号。

有个细节别忽略:

best[person] = candidate;

这行就是记忆化。

没有它,代码也能跑,但会反复查同一批富人链路。这个题的关系可能会重叠很多,缓存一加,整个图基本就只走一遍。

执行过程大概是这样:

查 0
  发现 1 比 0 富
    查 1
      发现 2 比 1 富
      发现 3 比 1 富
    得到 1 的最安静候选
  再和 0 自己比较
得到 0 的答案

这其实就是在图上做递归合并。

时间复杂度是 O(n + m),n 是人数,m 是 richer 关系数量。每个人只计算一次,每条边最多走一次。

这个题不用硬套最短路,也不用真给财富排序。关系已经给你了,顺着关系往上找,把每个人上游最安静的人缓存下来,就够了。