The "Loud and Rich" problem requires you to determine, for each person in a group, the quietest individual among all those who are at least as rich as that person (including themselves).
You are given:
n
, the number of people labeled from 0
to n - 1
.
richer
, where each element is a pair [a, b]
meaning person a
is richer than person b
.
quiet
, where quiet[i]
is the quietness score of person i
(lower means quieter).
answer
where answer[x]
is the index of the quietest person among all people who are at least as rich as person x
.
Constraints:
At first glance, the problem seems to ask for a "minimum" quietness value among all people who are as rich or richer than each person. Since the "richer" relationships form a directed graph (with an edge from richer to poorer), it is tempting to consider, for each person, all people who can reach them via these relationships.
A brute-force approach would be, for each person, to traverse the graph and collect all people richer than or equal to them, then select the quietest. However, this would be inefficient, especially if the graph is large or dense.
To optimize, we can think in terms of memoization or dynamic programming: once we've computed the quietest person for one node, we can reuse this result for others. This leads us to a depth-first search (DFS) approach with memoization, treating the problem as a propagation of "quietest so far" information from richer to poorer.
We'll model the "richer" information as a graph, where an edge from a
to b
means a
is richer than b
. For each person, we want to find the quietest person among themselves and all richer people.
[a, b]
in richer
, add a
to the list of "richer neighbors" for b
.x
, perform a DFS to find all richer people, keeping track of the quietest person found.We use a hash map (or adjacency list) for the graph to allow O(1) lookups, and memoization to avoid redundant DFS traversals.
Suppose richer = [[1,0],[2,1],[3,1]]
and quiet = [3,2,5,4]
.
The final answer is [1,1,2,3]
.
The optimized approach is efficient for large graphs, as each person's result is computed only once.
The "Loud and Rich" problem is a classic example of propagating minimum values through a directed acyclic graph. By modeling richer relationships as a graph and using DFS with memoization, we efficiently determine, for each person, the quietest among all those at least as rich as them. The key insight is to avoid recomputation by caching results, making the solution both elegant and efficient.
class Solution:
def loudAndRich(self, richer, quiet):
from collections import defaultdict
n = len(quiet)
graph = defaultdict(list)
for a, b in richer:
graph[b].append(a)
answer = [-1] * n
def dfs(x):
if answer[x] != -1:
return answer[x]
min_person = x
for neighbor in graph[x]:
candidate = dfs(neighbor)
if quiet[candidate] < quiet[min_person]:
min_person = candidate
answer[x] = min_person
return min_person
for i in range(n):
dfs(i)
return answer
class Solution {
public:
vector<int> loudAndRich(vector<vector<int>>& richer, vector<int>& quiet) {
int n = quiet.size();
vector<vector<int>> graph(n);
for (auto& r : richer) {
graph[r[1]].push_back(r[0]);
}
vector<int> answer(n, -1);
function<int(int)> dfs = [&](int x) {
if (answer[x] != -1) return answer[x];
int min_person = x;
for (int neighbor : graph[x]) {
int candidate = dfs(neighbor);
if (quiet[candidate] < quiet[min_person])
min_person = candidate;
}
answer[x] = min_person;
return min_person;
};
for (int i = 0; i < n; ++i)
dfs(i);
return answer;
}
};
class Solution {
public int[] loudAndRich(int[][] richer, int[] quiet) {
int n = quiet.length;
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i < n; ++i) graph.add(new ArrayList<>());
for (int[] r : richer) {
graph.get(r[1]).add(r[0]);
}
int[] answer = new int[n];
Arrays.fill(answer, -1);
returnInt[] dfs = new int[1];
for (int i = 0; i < n; ++i) {
dfs(i, graph, quiet, answer);
}
return answer;
}
private int dfs(int x, List<List<Integer>> graph, int[] quiet, int[] answer) {
if (answer[x] != -1) return answer[x];
int minPerson = x;
for (int neighbor : graph.get(x)) {
int candidate = dfs(neighbor, graph, quiet, answer);
if (quiet[candidate] < quiet[minPerson]) minPerson = candidate;
}
answer[x] = minPerson;
return minPerson;
}
}
var loudAndRich = function(richer, quiet) {
const n = quiet.length;
const graph = Array.from({length: n}, () => []);
for (const [a, b] of richer) {
graph[b].push(a);
}
const answer = new Array(n).fill(-1);
function dfs(x) {
if (answer[x] !== -1) return answer[x];
let minPerson = x;
for (const neighbor of graph[x]) {
const candidate = dfs(neighbor);
if (quiet[candidate] < quiet[minPerson]) minPerson = candidate;
}
answer[x] = minPerson;
return minPerson;
}
for (let i = 0; i < n; ++i) {
dfs(i);
}
return answer;
};