给你一个数组 pairs ,其中 pairs[i] = [xi, yi] ,并且满足:
pairs 中没有重复元素
xi < yi
令 ways 为满足下面条件的有根树的方案数:
树所包含的所有节点值都在 pairs 中。
一个数对 [xi, yi] 出现在 pairs 中 当且仅当 xi 是 yi 的祖先或者 yi 是 xi 的祖先。
注意:构造出来的树不一定是二叉树。
两棵树被视为不同的方案当存在至少一个节点在两棵树中有不同的父节点。
请你返回:
如果 ways == 0 ,返回 0 。
如果 ways == 1 ,返回 1 。
如果 ways > 1 ,返回 2 。
一棵 有根树 指的是只有一个根节点的树,所有边都是从根往外的方向。
我们称从根到一个节点路径上的任意一个节点(除去节点本身)都是该节点的 祖先 。根节点没有祖先。
示例 1:
输入:pairs = [[1,2],[2,3]]
输出:1
解释:如上图所示,有且只有一个符合规定的有根树。
示例 2:
输入:pairs = [[1,2],[2,3],[1,3]]
输出:2
解释:有多个符合规定的有根树,其中三个如上图所示。
示例 3:
输入:pairs = [[1,2],[2,3],[2,4],[1,5]]
输出:0
解释:没有符合规定的有根树。
提示:
1 <= pairs.length <= 105
1 <= xi < yi <= 500
pairs 中的元素互不相同。
PS:很久之前的一道周赛压轴题了,仍记得当时写完三道题后挂机一个多小时的无奈,还是自己太菜呀
对于该题,核心内容无非两点:
(1)点u是点v的祖先,则与u相关的关系数要大于等于v,当且仅当u和v在一条链上,并且没有分支的时候取等号
(2)若两个点的关系数相同并且不在v还没有遍历到,我们需要知道此时u和v的祖先,若两个点的祖先相等,我们令v的祖先为u,若不想等,则是非法情况【上述链接讲解的非常清楚,为这边就不过多赘述】。
class Solution {
private static final int size = 501;
public int checkWays(int[][] pairs) {
int ans = 1;
int m = pairs.length;
int[] pre = new int[size];
int[] nums = new int[size];
boolean[] vis = new boolean[size];
List<int[]> list = new ArrayList<>();
List<List<Integer>> edges = new ArrayList<>();
for (int i = 0; i < size; i++)
edges.add(new ArrayList<>());
for (int i = 0; i < m; i++) {
int u = pairs[i][0];
int v = pairs[i][1];
nums[u]++;
nums[v]++;
edges.get(u).add(v);
edges.get(v).add(u);
pre[u] = pre[v] = -1;
}
for (int i = 0; i < size; i++) {
if (nums[i] == 0)
continue;
list.add(new int[]{i, nums[i]});
}
int sz = list.size();
Collections.sort(list, (a, b) -> (b[1] - a[1]));
if (nums[list.get(0)[0]] != sz - 1) return 0;
for (int i = 0; i < sz; i++) {
int u = list.get(i)[0];
int len = edges.get(u).size();
for (int j = 0; j < len; j++) {
int v = edges.get(u).get(j);
if (nums[v] == nums[u])
ans = 2;
if (!vis[v]) {
if (pre[u] != pre[v])
return 0;
pre[v] = u;
}
vis[u] = true;
}
}
return ans;
}
}