有一组 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.深度优先遍历
题目需要找比当前节点富有的人。深度优先遍历的图结构是穷人指向富人,递归遍历的过程中对富有的人赋值。
2.拓扑排序
拓扑排序的图结构是富人指向穷人,知道根节点的值,拓扑序列的其他点的值就可以确定了。
深度优先遍历
class Solution {
public:
vector<int>res;
void dfs(vector<vector<int>>& graph, vector<int>& quiet,int cur){
if(res[cur]!=-1){
return ; //已经遍历过,直接返回
}
res[cur]=cur; //初始化为本身
for(int i=0;i<graph[cur].size();i++){
dfs(graph,quiet,graph[cur][i]);
if(quiet[res[cur]]>quiet[res[graph[cur][i]]]){
res[cur]=res[graph[cur][i]];
}
}
}
vector<int> loudAndRich(vector<vector<int>>& richer, vector<int>& quiet) {
int n=quiet.size();
res.resize(n);
for(int i=0;i<n;i++){//res初始化为-1,表示还没有遍历过
res[i]=-1;
}
vector<vector<int>>graph(n,vector<int>(0));//图,穷人指向富人。
for(int i=0;i<richer.size();i++){
graph[richer[i][1]].push_back(richer[i][0]);
}
for(int i=0;i<n;i++){
dfs(graph,quiet,i);
}
return res;
}
};
拓扑排序
class Solution {
public:
vector<int> loudAndRich(vector<vector<int>>& richer, vector<int>& quiet) {
int n=quiet.size();
vector<vector<int>>graph(n,vector<int>(0));//图,富人指向穷人
vector<int>indegree(n); //每个节点的入度,入度为0的点是拓扑序列的根节点
queue<int>q;//保存入度为0的点
for(int i=0;i<richer.size();i++){
graph[richer[i][0]].push_back(richer[i][1]);
indegree[richer[i][1]]++;
}
for(int i=0;i<n;i++){
if(indegree[i]==0){
q.push(i);
}
}
vector<int>res(n);
iota(res.begin(),res.end(),0); //初始化每个节点的结果是本身
while(!q.empty()){
int cur=q.front();
q.pop();
for(auto x:graph[cur]){
indegree[x]--;
if(indegree[x]==0){ //如果入度为0,加入到队列中
q.push(x);
}
if(quiet[res[cur]]<quiet[res[x]]){ //如果富人的安静值比x的安静值更低,更新x的结果
res[x]=res[cur];
}
}
}
return res;
}
};