LC 1583. 统计不开心的朋友
题目描述
这是 LeetCode 上的 1583. 统计不开心的朋友 ,难度为 中等。
给你一份 n
位朋友的亲近程度列表,其中 n
总是偶数 。
对每位朋友 i
,preferences[i]
包含一份 按亲近程度从高到低排列 的朋友列表。
换句话说,排在列表前面的朋友与 i
的亲近程度比排在列表后面的朋友更高。每个列表中的朋友均以 0
到 n-1
之间的整数表示。
所有的朋友被分成几对,配对情况以列表 pairs
给出,其中 pairs[i] = [xi, yi]
表示 xi
与 yi
配对,且 yi
与 xi
配对。
但是,这样的配对情况可能会是其中部分朋友感到不开心。在 x
与 y
配对且 u
与 v
配对的情况下,如果同时满足下述两个条件,x
就会不开心:
x
与u
的亲近程度胜过x
与y
,且u
与x
的亲近程度胜过u
与v
返回 不开心的朋友的数目 。
示例 1:1
2
3
4
5
6
7
8
9
10
11
12输入:n = 4, preferences = [[1, 2, 3], [3, 2, 0], [3, 1, 0], [1, 2, 0]], pairs = [[0, 1], [2, 3]]
输出:2
解释:
朋友 1 不开心,因为:
- 1 与 0 配对,但 1 与 3 的亲近程度比 1 与 0 高,且
- 3 与 1 的亲近程度比 3 与 2 高。
朋友 3 不开心,因为:
- 3 与 2 配对,但 3 与 1 的亲近程度比 3 与 2 高,且
- 1 与 3 的亲近程度比 1 与 0 高。
朋友 0 和 2 都是开心的。
示例 2:1
2
3
4
5输入:n = 2, preferences = [[1], [0]], pairs = [[1, 0]]
输出:0
解释:朋友 0 和 1 都开心。
示例 3:1
2
3输入:n = 4, preferences = [[1, 3, 2], [2, 3, 0], [1, 3, 0], [0, 2, 1]], pairs = [[1, 3], [0, 2]]
输出:4
提示:
- 2 <= n <= 500
- n 是偶数
- preferences.length == n
- preferences[i].length == n - 1
- 0 <= preferences[i][j] <= n - 1
- preferences[i] 不包含 i
- preferences[i] 中的所有值都是独一无二的
- pairs.length == n/2
- pairs[i].length == 2
- xi != yi
- 0 <= xi, yi <= n - 1
- 每位朋友都 恰好 被包含在一对中
模拟
模拟题,先将所有的 $preferences$ 使用「哈希表套哈希表」的形式进行存储,存储格式为 {x : {y : score1}, {z : score12}, ... }
。
如果 $x$ 和 $y$ 的亲密度要比 $x$ 和 $z$ 的亲密度要高,则有 $score1 > score2$。利用原本 $preferences[i]$ 就是按照亲密度进行排序,我们可以对下标进行转换作为亲密数得分即可。
然后对所有的 $pairs$ 进行遍历,统计所有的答案,注意一个小朋友只能被统计一次。
当然利用 $n$ 的数据范围,直接使用二维数组充当哈希表也是可以的(见 $P2$)
代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34class Solution {
Map<Integer, Map<Integer, Integer>> map = new HashMap<>();
public int unhappyFriends(int n, int[][] preferences, int[][] pairs) {
int m = pairs.length;
for (int i = 0; i < n; i++) {
int[] p = preferences[i];
Map<Integer, Integer> cur = new HashMap<>();
for (int j = 0; j < n - 1; j++) cur.put(p[j], n - j);
map.put(i, cur);
}
int ans = 0;
for (int i = 0; i < m; i++) {
int x = pairs[i][0], y = pairs[i][1];
boolean xok = false, yok = false;
for (int j = 0; j < m; j++) {
if (i == j) continue;
int u = pairs[j][0], v = pairs[j][1];
if (!xok && check(x, y, u, v)) xok = true;
if (!yok && check(y, x, u, v)) yok = true;
if (xok && yok) break;
}
if (xok) ans++;
if (yok) ans++;
}
return ans;
}
boolean check(int x, int y, int u, int v) {
Map<Integer, Integer> xmap = map.get(x), ymap = map.get(y);
Map<Integer, Integer> umap = map.get(u), vmap = map.get(v);
if (xmap.get(u) > xmap.get(y) && umap.get(x) > umap.get(v)) return true;
if (xmap.get(v) > xmap.get(y) && vmap.get(x) > vmap.get(u)) return true;
return false;
}
}
代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31class Solution {
int N = 510;
int[][] map = new int[N][N];
public int unhappyFriends(int n, int[][] preferences, int[][] pairs) {
int m = pairs.length;
for (int i = 0; i < n; i++) {
int[] p = preferences[i];
for (int j = 0; j < n - 1; j++) map[i][p[j]] = n - j;
}
int ans = 0;
for (int i = 0; i < m; i++) {
int x = pairs[i][0], y = pairs[i][1];
boolean xok = false, yok = false;
for (int j = 0; j < m; j++) {
if (i == j) continue;
int u = pairs[j][0], v = pairs[j][1];
if (!xok && check(x, y, u, v)) xok = true;
if (!yok && check(y, x, u, v)) yok = true;
if (xok && yok) break;
}
if (xok) ans++;
if (yok) ans++;
}
return ans;
}
boolean check(int x, int y, int u, int v) {
if (map[x][u] > map[x][y] && map[u][x] > map[u][v]) return true;
if (map[x][v] > map[x][y] && map[v][x] > map[v][u]) return true;
return false;
}
}
- 时间复杂度:预处理出
map
的复杂度为 $O(n^2)$;遍历统计答案的复杂度为 $O(n^2)$。整体复杂度为 $O(n^2)$ - 空间复杂度:$O(n^2)$
最后
这是我们「刷穿 LeetCode」系列文章的第 No.1583
篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!