【图论】C003_找到小镇的法官(dfs 判环?/ 统计出入度)

一、题目描述

In a town, there are N people labelled from 1 to N. There is a rumor that one of these people is secretly the town judge.

If the town judge exists, then:

The town judge trusts nobody.
Everybody (except for the town judge) trusts the town judge.
There is exactly one person that satisfies properties 1 and 2.
You are given trust, an array of pairs trust[i] = [a, b] representing that the person labelled a trusts the person labelled b.

If the town judge exists and can be identified, return the label of the town judge. Otherwise, return -1.

Input: N = 3, trust = [[1,3],[2,3]]
Output: 3

Input: N = 3, trust = [[1,3],[2,3],[3,1]]
Output: -1

二、题解

题意:[a, b] 表示 a 相信 b,所有点构成了一个有向图,找到被所有人相信但自己不相信任何人的那个人。

方法一:dfs 判环?

错误思想:如果图存在环,则不存在法官。否则,返回入度为 N-1 的人。

A1:因为并没有标明除了法官的其它人不能互相信任,即图中存在环,也是可以有法官的。比如:

4
[[1,2],[1,3],[2,1],[2,3],[1,4],[4,3],[4,1]]
预期:3
输出:-1
boolean[] ving, ved;
Map<Integer, List<Integer>> graph;
public int findJudge(int N, int[][] edges) {
    graph = new HashMap<>();
    for (int i = 1; i <= N; i++) {
        graph.put(i, new LinkedList<>());
    }
    for (int[] edge : edges) {
        graph.get(edge[1]).add(edge[0]);
    }
    ving = new boolean[N+1];
    ved = new boolean[N+1];
    for (int i = 1; i <= N; i++) {
        if (dfs(i))
            return -1;
    }
    int[] in = new int[1000+50];
    for (int[] t : edges) {
        in[t[1]]++;
    }
    for (int i = 1; i <= N; i++) {
        if (in[i] == N-1)
        return i;
    }
    return -1;
}
private boolean dfs(int i) {
    //证明有环
    if (ving[i]) return true;
    if (ved[i])  return false;
    ving[i] = true;
    for (int toTake : graph.get(i)) {
        if (dfs(toTake))
            return true;
    }
    ving[i] = false;
    ved[i] = true;
    return false;
}

方法二:统计出入度

因为法官的入度为 N-1,出度一定是 0,所以只需要统计一遍即可。

public int findJudge(int N, int[][] edges) {
    int[] in = new int[N+1];
    int[] out = new int[N+1];
    for (int[] edge : edges) {
        in[edge[1]]++;
        out[edge[0]]++;
    }
    for (int i = 1; i <= N; i++) {
        if (in[i] == N-1 && out[i] == 0)
            return i;
    }
    return -1;
}

复杂度分析

  • 时间复杂度: O ( n ) O(n)
  • 空间复杂度: O ( n ) O(n)

方法三:邻接矩阵记录信息

  • 在 N × N 的矩阵中,用 1 表示信任,0 表示不存在信任。
  • 如果有某个人是法官,那么一定存在 1 列全是 1,一行中除了自己全是 0
public int findJudge(int N, int[][] edges) {
    int[][] matrix = new int[N+1][N+1];
    
    for (int[] edge : edges) {
        matrix[edge[0]][edge[1]] = 1; 
    }
    for (int i = 1; i <= N; i++) {
        matrix[i][i] = 1;
    }
    
    for (int c = 1; c <= N; c++) {
        boolean isAllOne = true;
        for (int r = 1; r <= N; r++) {
            if (matrix[r][c] == 0) {
                isAllOne = false;
                break;
            }
        }
        if (isAllOne == false)
            continue;
        boolean found = true;
        for (int k = 1; k <= N; k++) {
            if (matrix[c][k] == 1 && c != k) {
                found = false;
                break;
            }
        }
        if (found) 
            return c;;
    }
    return -1;
}

复杂度分析

  • 时间复杂度: O ( n 2 ) O(n^2)
  • 空间复杂度: O ( n 2 ) O(n^2)
发布了691 篇原创文章 · 获赞 151 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/105449857