LC 851. 喧闹和富有
题目描述
这是 LeetCode 上的 851. 喧闹和富有 ,难度为 中等。
有一组 n
个人作为实验对象,从 0
到 n - 1
编号,其中每个人都有不同数目的钱,以及不同程度的安静值(quietness
)。为了方便起见,我们将编号为 x
的人简称为 "person x"
。
给你一个数组 richer
,其中 richer[i] = [ai, bi]
表示 $person$ $a_i$ 比 $person$ $b_i$ 更有钱。另给你一个整数数组 quiet
,其中 quiet[i]
是 $person_i$ 的安静值。
richer
中所给出的数据 逻辑自恰(也就是说,在 $person_x$ 比 $person_y$ 更有钱的同时,不会出现 $person_y$ 比 $person_x$ 更有钱的情况 )。
现在,返回一个整数数组 answer
作为答案,其中 answer[x] = y
的前提是,在所有拥有的钱肯定不少于 person x
的人中,person y
是最安静的人(也就是安静值 quiet[y]
最小的人)。
示例 1:1
2
3
4
5
6
7
8
9
10
11
12
13输入:richer = [[1,0],[2,1],[3,1],[3,7],[4,3],[5,3],[6,3]], quiet = [3,2,5,4,6,1,7,0]
输出:[5,5,2,5,4,5,6,7]
解释:
answer[0] = 5,
person 5 比 person 3 有更多的钱,person 3 比 person 1 有更多的钱,person 1 比 person 0 有更多的钱。
唯一较为安静(有较低的安静值 quiet[x])的人是 person 7,
但是目前还不清楚他是否比 person 0 更有钱。
answer[7] = 7,
在所有拥有的钱肯定不少于 person 7 的人中(这可能包括 person 3,4,5,6 以及 7),
最安静(有较低安静值 quiet[x])的人是 person 7。
其他的答案也可以用类似的推理来解释。
示例 2:1
2
3输入:richer = [], quiet = [0]
输出:[0]
提示:
- $n == quiet.length$
- $1 <= n <= 500$
- $0 <= quiet[i] < n$
- $quiet$ 的所有值 互不相同
- $0 <= richer.length <= n * (n - 1) / 2$
- $0 <= ai, bi < n$
- $ai != bi$
richer
中的所有数对 互不相同- 对
richer
的观察在逻辑上是一致的
拓扑排序
根据题意,我们可以使用 richer
进行建图(邻接矩阵/邻接表),对于每组 $richer[i] = (a_i, b_i)$ 而言,添加一条从 $a$ 到 $b$ 的有向边(有钱指向没钱)。
其中题目中的「richer
逻辑自恰」是指在该图中不存在环,即为 DAG。
因此我们可以在建图过程中,同时统计每个节点的入度数,然后在图中跑一遍拓扑排序来求得答案 $ans$。
对「图论 拓扑排序」不了解的同学,可以先看前置 🧀:拓扑排序入门,里面详细说明了「拓扑排序的基本流程」&「反向图 + 拓扑排序做法的正确性证明」。
起始时,每个 $ans[i] = i$,然后将统计入度为 $0$ 的节点进行入队,每次出队时,将该节点删掉,对该 DAG 带来影响是「该节点的邻点的入度减一」,若更新入度后数值为 $0$,则将该邻点进行入队操作。
同时,利用跑拓扑排序过程中的 $t -> u$ 关系,尝试使用 $ans[t]$ 更新 $ans[u]$(由于存在 $t$ 指向 $u$ 的边,说明 $t$ 比 $u$ 有钱,此时检查两者的安静值,若满足 $quiet[ans[t]] < quiet[ans[u]]$,则用 $ans[t]$ 更新 $ans[u]$)。
本题为稠密图(点数为 $n$,边数为 $m$,当 $m$ 与 $n^2$ 为同一数据级,定义以为稠密图),可直接使用「邻接矩阵」进行存图。
关于何种图选择什么存图方式,在 这里 详细讲过,本次不再赘述。
代码($P1$ 为邻接矩阵,$P2$ 为邻接表):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27class Solution {
public int[] loudAndRich(int[][] richer, int[] quiet) {
int n = quiet.length;
int[][] w = new int[n][n];
int[] in = new int[n];
for (int[] r : richer) {
int a = r[0], b = r[1];
w[a][b] = 1; in[b]++;
}
Deque<Integer> d = new ArrayDeque<>();
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = i;
if (in[i] == 0) d.addLast(i);
}
while (!d.isEmpty()) {
int t = d.pollFirst();
for (int u = 0; u < n; u++) {
if (w[t][u] == 1) {
if (quiet[ans[t]] < quiet[ans[u]]) ans[u] = ans[t];
if (--in[u] == 0) d.addLast(u);
}
}
}
return ans;
}
}
1 |
|
- 时间复杂度:令 $n$ 为
person
数量(点数),$m$ 为richer
长度(边数)。的建图的复杂度为 $O(m)$;拓扑排序复杂度为 $O(m + n)$。整体复杂度为 $O(m + n)$ - 空间复杂度:$O(m + n)$
最后
这是我们「刷穿 LeetCode」系列文章的第 No.851
篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!