「这是我参与2022首次更文挑战的第 8 天,活动详情查看:2022首次更文挑战」
题目链接
997. 找到小镇的法官 - 力扣(LeetCode) (leetcode-cn.com)
题目描述
小镇里有 n 个人,按从 1 到 n 的顺序编号。传言称,这些人中有一个暗地里是小镇法官。
如果小镇法官真的存在,那么:
- 小镇法官不会信任任何人。
- 每个人(除了小镇法官)都信任这位小镇法官。
- 只有一个人同时满足属性 1 和属性 2 。
给你一个数组 trust ,其中 trust[i] = [ai, bi] 表示编号为 ai 的人信任编号为 bi 的人。
如果小镇法官存在并且可以确定他的身份,请返回该法官的编号;否则,返回 -1 。
测试用例
示例 1:
输入:n = 2, trust = [[1,2]]
输出:2
示例 2:
输入:n = 3, trust = [[1,3],[2,3]]
输出:3
题目分析
分析题意,可知,这是一个有向图的模型。存在 n 个点,这些点之间存在单向的连线。需要我们判断,图上面,是否存在这么一个点,使得其余的点都单向的指向它,并且,这个点只有其余点到它的连线,而没有它去其余点的线
图的关系数据,以一个二维数组的形式,存放在 trust 变量当中
一个比较合适的做法就是,遍历 trust 数组,将它的数据以邻接表的形式整理出来,在 js 中就用 Object + Set 的方式来模拟
然后,我们检查 obj 中的 key 的数据,如果刚好有 1 个点不在 key 里,这个点就是法官。然后,我们去检查每个 key 对应的 set 数据,判断是否都包含了“法官”,一旦有 1 个没有,就返回 -1
代码实现
var findJudge = function(n, trust) {
if (n > trust.length + 1) return -1;
let obj = {};
trust.forEach(t => {
let arr = obj[t[0]] || new Set();
arr.add(t[1]);
obj[t[0]] = arr;
})
let ks = Object.keys(obj);
if (.length + 1 != n) return -1;
let key = new Array(n).fill(0).map((m, i) => i + 1).reduce((a, b) => a ^ b, 0) ^ ks.reduce((a, b) => a ^ b, 0);
for (let i = 0; i < ks.length; i++) {
if (!obj[ks[i]].has(key)) return -1;
}
return key;
};
因为遍历了 trust 并使用了另一个数据结构来获取答案,所以时间和空间上的花费较大
优化
那么,我们换个思路,对每个点进行信任计数:比如,点1 信任了其他点,点1 的计数 -1;如果点1 被其他点信任,点1 计数 +1;最后,只需要判断是否存在一个计数为 n-1 的点即可
代码如下:
var findJudge = function(n, trust) {
if (n == 1) return 1;
let arr = new Array(n + 1).fill(0);
trust.forEach(t => {
arr[t[0]] -= 1;
arr[t[1]] += 1;
})
for (let i = 0; i < arr; i++) {
if (arr[i] == n - 1) {
return i;
}
}
return -1;
};
思路的优化,以及存储结构由对象替换为数组,效率逼近双百