有一组 n 个人作为实验对象,从 0 到 n - 1 编号,其中每个人都有不同数目的钱,以及不同程度的安静值(quietness)。为了方便起见,我们将编号为 x 的人简称为 “person x “。
给你一个数组 richer ,其中 richer[i] = [ai, bi] 表示 person ai 比 person bi 更有钱。另给你一个整数数组 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:
**输入:** 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。
其他的答案也可以用类似的推理来解释。
题目需要计算拥有的钱肯定不少于 x 的人中,最安静的人。我们可以分为拥有的钱肯定与 x 相等,以及拥有的钱肯定比 x 多两种情况。对于前者,根据题目所给信息,我们只知道 x 拥有的钱肯定与自己相等,无法知道是否有其他人拥有的钱肯定与 x 相等;对于后者,我们可以先计算出 x 的邻居的 answer 值,再取这些 answer 值中的最小值为结果,这是因为从 x 的邻居出发所能访问到的点,并上 x 的邻居后所得到的点集,就是从 x 出发所能访问到的点。总的来说,最安静的人要么是 x 自己,要么是 x 的邻居的 answer 中最安静的人。
计算 x 的每个邻居的 answer 值是一个递归的过程,我们可以用深度优先搜索来实现。为避免重复运算,在已经计算出 answer}[x] 的情况下可以直接返回。
[sol1-Python3]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution: defloudAndRich(self, richer: List[List[int]], quiet: List[int]) -> List[int]: n = len(quiet) g = [[] for _ inrange(n)] for r in richer: g[r[1]].append(r[0])
ans = [-1] * n defdfs(x: int): if ans[x] != -1: return ans[x] = x for y in g[x]: dfs(y) if quiet[ans[y]] < quiet[ans[x]]: ans[x] = ans[y] for i inrange(n): dfs(i) return ans
publicclassSolution { publicint[] LoudAndRich(int[][] richer, int[] quiet) { int n = quiet.Length; IList<int>[] g = new List<int>[n]; for (int i = 0; i < n; ++i) { g[i] = new List<int>(); } foreach (int[] r in richer) { g[r[1]].Add(r[0]); }
int[] ans = newint[n]; Array.Fill(ans, -1); for (int i = 0; i < n; ++i) { DFS(i, quiet, g, ans); } return ans; }
funcloudAndRich(richer [][]int, quiet []int) []int { n := len(quiet) g := make([][]int, n) for _, r := range richer { g[r[1]] = append(g[r[1]], r[0]) }
ans := make([]int, n) for i := range ans { ans[i] = -1 } var dfs func(int) dfs = func(x int) { if ans[x] != -1 { return } ans[x] = x for _, y := range g[x] { dfs(y) if quiet[ans[y]] < quiet[ans[x]] { ans[x] = ans[y] } } } for i := 0; i < n; i++ { dfs(i) } return ans }
var loudAndRich = function(richer, quiet) { const n = quiet.length; const g = newArray(n).fill(0); for (let i = 0; i < n; ++i) { g[i] = []; } for (const r of richer) { g[r[1]].push(r[0]); }
const ans = newArray(n).fill(-1); for (let i = 0; i < n; ++i) { dfs(i, quiet, g, ans); } return ans; };
constdfs = (x, quiet, g, ans) => { if (ans[x] !== -1) { return; } ans[x] = x; for (const y of g[x]) { dfs(y, quiet, g, ans); if (quiet[ans[y]] < quiet[ans[x]]) { ans[x] = ans[y]; } } }
classSolution: defloudAndRich(self, richer: List[List[int]], quiet: List[int]) -> List[int]: n = len(quiet) g = [[] for _ inrange(n)] inDeg = [0] * n for r in richer: g[r[0]].append(r[1]) inDeg[r[1]] += 1
ans = list(range(n)) q = deque(i for i, deg inenumerate(inDeg) if deg == 0) while q: x = q.popleft() for y in g[x]: if quiet[ans[x]] < quiet[ans[y]]: ans[y] = ans[x] # 更新 x 的邻居的答案 inDeg[y] -= 1 if inDeg[y] == 0: q.append(y) return ans
publicclassSolution { publicint[] LoudAndRich(int[][] richer, int[] quiet) { int n = quiet.Length; IList<int>[] g = new List<int>[n]; for (int i = 0; i < n; ++i) { g[i] = new List<int>(); } int[] inDeg = newint[n]; foreach (int[] r in richer) { g[r[0]].Add(r[1]); ++inDeg[r[1]]; }
int[] ans = newint[n]; for (int i = 0; i < n; ++i) { ans[i] = i; } Queue<int> q = new Queue<int>(); for (int i = 0; i < n; ++i) { if (inDeg[i] == 0) { q.Enqueue(i); } } while (q.Count > 0) { int x = q.Dequeue(); foreach (int y in g[x]) { if (quiet[ans[x]] < quiet[ans[y]]) { ans[y] = ans[x]; // 更新 x 的邻居的答案 } if (--inDeg[y] == 0) { q.Enqueue(y); } } } return ans; } }
funcloudAndRich(richer [][]int, quiet []int) []int { n := len(quiet) g := make([][]int, n) inDeg := make([]int, n) for _, r := range richer { g[r[0]] = append(g[r[0]], r[1]) inDeg[r[1]]++ }
ans := make([]int, n) for i := range ans { ans[i] = i } q := make([]int, 0, n) for i, deg := range inDeg { if deg == 0 { q = append(q, i) } } forlen(q) > 0 { x := q[0] q = q[1:] for _, y := range g[x] { if quiet[ans[x]] < quiet[ans[y]] { ans[y] = ans[x] // 更新 x 的邻居的答案 } inDeg[y]-- if inDeg[y] == 0 { q = append(q, y) } } } return ans }
var loudAndRich = function(richer, quiet) { const n = quiet.length; const g = newArray(n).fill(0); for (let i = 0; i < n; ++i) { g[i] = []; } const inDeg = newArray(n).fill(0); for (const r of richer) { g[r[0]].push(r[1]); ++inDeg[r[1]]; }
const ans = newArray(n).fill(0); for (let i = 0; i < n; ++i) { ans[i] = i; } const q = []; for (let i = 0; i < n; ++i) { if (inDeg[i] === 0) { q.push(i); } } while (q.length) { const x = q.shift(); for (const y of g[x]) { if (quiet[ans[x]] < quiet[ans[y]]) { ans[y] = ans[x]; // 更新 x 的邻居的答案 } if (--inDeg[y] === 0) { q.push(y); } } } return ans; };
复杂度分析
时间复杂度:O(n+m),其中 n 是数组 quiet 的长度,m 是数组 richer 的长度。建图和拓扑排序的时间复杂度均为 O(n+m)。