leetcode
leetcode 751 ~ 800
喧闹和富有

喧闹和富有

难度:

标签:

题目描述

代码结果

运行时间: 38 ms, 内存: 22.7 MB


/*
 * 题目思路:
 * 同样,我们需要使用拓扑排序解决问题。但我们可以利用Java Stream来构建和处理数据。
 * 1. 构建邻接表和入度数组。
 * 2. 使用Java Stream初始化队列。
 * 3. 使用Stream进行队列操作和更新安静值最小者。
 */
import java.util.*;
import java.util.stream.*;

public class Solution {
    public int[] loudAndRich(int[][] richer, int[] quiet) {
        int n = quiet.length;
        List<List<Integer>> graph = IntStream.range(0, n)
                .mapToObj(i -> new ArrayList<Integer>())
                .collect(Collectors.toList());
        int[] indegree = new int[n];
        Arrays.stream(richer).forEach(pair -> {
            graph.get(pair[0]).add(pair[1]);
            indegree[pair[1]]++;
        });
        int[] answer = IntStream.range(0, n).toArray();
        Queue<Integer> queue = IntStream.range(0, n)
                .filter(i -> indegree[i] == 0)
                .boxed()
                .collect(Collectors.toCollection(LinkedList::new));
        while (!queue.isEmpty()) {
            int person = queue.poll();
            graph.get(person).forEach(richerPerson -> {
                if (quiet[answer[person]] < quiet[answer[richerPerson]]) {
                    answer[richerPerson] = answer[person];
                }
                if (--indegree[richerPerson] == 0) queue.offer(richerPerson);
            });
        }
        return answer;
    }
}

解释

方法:

这道题目可以使用深度优先搜索(DFS)来解决。首先,我们根据richer数组构建一个图g,其中g[y]包含所有比person y更有钱的人。然后,我们初始化一个答案数组ans,其中ans[x]表示在所有拥有的钱不少于person x的人中,最不安静的人的编号。我们对每个人i进行深度优先搜索,搜索过程中,如果我们访问到一个人x,我们首先检查ans[x]是否已经被计算过,如果没有,我们将ans[x]初始化为x自身,然后对于x的每一个财富大于他的人y,我们递归地调用dfs(y),并更新ans[x]为quiet值最小的人。最终,ans数组就是我们的答案。

时间复杂度:

O(r + n)

空间复杂度:

O(n)

代码细节讲解

🦆
如何确保构建的图g不会有环,从而使得DFS可以安全执行而不陷入无限循环?
在题解中,图g的构建基于richer数组,其中每个元素[x, y]表示x比y更富有。在这种情况下,我们构建的是一个有向图,其中方向代表'更富有'这一关系。由于'更富有'是严格的单向关系(A比B富有不意味着B也比A富有),因此理论上不应存在环。也就是说,'更富有'关系应该构成了一个拓扑排序。然而,为了在实现中保证安全且环不存在,我们可以在执行DFS之前,使用拓扑排序检测算法如Kahn算法或通过DFS检测环的存在,确保这一点。
🦆
在DFS过程中,如果存在多个人拥有相同的安静值,答案数组ans如何决定选取哪一个人作为最不安静的人?是否有特定的规则?
在实现DFS和更新ans数组时,如果多个人拥有相同的最小安静值,题解中的算法默认保留在ans[x]中首先找到的那个人的编号。由于DFS的性质和图的构建方式,通常这意味着节点ID较小的人将被优先考虑。这是由于在构建图g时加入节点的顺序以及递归调用的顺序决定的。
🦆
在构建图g时,是否有考虑到某些人可能没有比他们更有钱的人,即某些列表可能为空的情况?这种情况如何处理?
是的,在构建图g时,确实考虑了列表可能为空的情况。对于那些没有比他们更有钱的人的个体,他们在图g中对应的列表将为空。在DFS执行过程中,当遇到这样的个体时,由于他们没有更有钱的人,DFS将不会进一步递归调用,而是直接将该人的编号作为答案保留在ans中,因为他们自己就是在其可达群体中最不安静的人。
🦆
题解中没有明确说明如何处理已计算过的ans[x],在实际代码中是如何避免对同一节点重复计算的?
实际代码中使用了一个简单的检查来避免对同一节点重复计算。在DFS函数的开始,会检查ans[x]是否已经不是初始化值(在这种情况下是-1)。如果ans[x]不是-1,这意味着我们之前已经计算过x的值,因此可以直接返回而不需要再次计算。这个机制确保了每个节点只被计算一次,从而防止了不必要的重复工作和潜在的无限循环。

相关问题