851. 喧闹和富有

目录

题意分析

算法思路

一、dfs搜索

二、拓扑排序

代码实现

dfs

拓扑

总结


题意分析

 喧闹和富有 - 喧闹和富有 - 力扣(LeetCode)

这道题其实就是找邻居里顶点值最小的。一个很直观的想法就是dfs搜索,又由于存在“富有”关系,也就是有向无环图,所以遍历搜索时也可以采用拓扑排序的方法解决。

算法思路

参考了题解,发现写的比我的屎山好多了。

两个方法都要先建立好邻接表,所以就不重复了,这是每个图题的必须操作。这里只提下关键思路。

一、dfs搜索

要求最小的顶点值,一种可能就是本身最小,一种就是我的邻接表内的点的顶点值最小,所以可以深搜来解决。注意到搜索有些搜索情况是重复的,为了提高效率我们要做个记忆化。所以

  1. 创立记忆数组,记录遍历结果
  2. 如果顶点没遍历过,将记忆数组初始化为当前顶点的值
  3. 遍历该顶点的邻接点,如果临接点更小,更新
  4. 返回结果,输出

二、拓扑排序

也就将入度为0的顶点先遍历输出即可,不过注意此处图存储顺序反了,因为要找富人里最安静的,所以最富有的人就不需要遍历了。

  1. 创建入度数组
  2. 创建队列,将入度为0的顶点入队
  3. 弹出顶点,因为入度为0,所以如果邻居比它的值大,更新邻居就可以了。
  4. 队列为空,结束输出。

代码实现

dfs

class Solution {
public:
    vector<vector<int>> g;
    vector<int> ans;
    vector<int> loudAndRich(vector<vector<int>>& richer, vector<int>& quiet) {
        int n=richer.size(),m=quiet.size();
        g.resize(m);
        ans.resize(m,-1);
        for(auto & r:richer){
            g[r[1]].emplace_back(r[0]);
        }
        for(int i=0;i<m;i++){
            dfs(i,quiet);
        }
        return ans;
    }
    void dfs(int cur,vector<int>&quiet){
        if(ans[cur]!=-1) return ;
        ans[cur]=cur;
        for(auto & nxt:g[cur]){
            dfs(nxt,quiet);
            if(quiet[ans[nxt]]<quiet[ans[cur]]){
                ans[cur]=ans[nxt];
            }
        }
    }
};

拓扑

class Solution {
public:
    vector<int> loudAndRich(vector<vector<int>>& richer, vector<int>& quiet) {
        int m=quiet.size();
        vector<vector<int>> g(m);
        vector<int> indegree(m,0);
        for(auto & r:richer){
            g[r[0]].emplace_back(r[1]);
            indegree[r[1]]++;
        }
        queue<int> q;
        for(int i=0;i<m;i++){
            if(indegree[i]==0) q.emplace(i);
        }
        vector<int> ans(m);
        iota(ans.begin(),ans.end(),0);//连续编号函数
        while(!q.empty()){
            int cur=q.front();q.pop();
            for(auto & nxt:g[cur]){
                if(quiet[ans[nxt]]>quiet[ans[cur]]){
                    ans[nxt]=ans[cur];
                }
                if(--indegree[nxt]==0) q.emplace(nxt);
            }
        }
        return ans;
    }
};

总结

这题是一道图的遍历问题,也比较经典吧,2个方法值得多理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值