来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-ways-to-reconstruct-a-tree
题目描述
给你一个数组 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 中的元素互不相同。
解题思路
这道题确实很难。光是思路就十分难想。
首先,如果是一棵树,那么他肯定有一个根结点,并且这个根结点与其他结点的连接数应该是n-1 所以,我们可以统计所有结点的连接数,如果没有n-1的结点,那么可以判断无法构成一棵树。
已知如果一个结点是某些结点的祖先,那么其父节点也是这些结点的祖先。所以我们依次判断结点的父结点连接的结点是否全部包含该结点所连接的结点。
寻找父节点的方法是寻找该结点中,结点连接数最小的并且连接数大于等于该结点的连接数的结点,则这个结点就是该结点的父结点。同时,如果一个结点与其父节点连接数相同,那么他们可以互相交换,这种情况发生就表示构成的树种类大于1。
代码展示
class Solution { public: int checkWays(vector<vector<int>>& pairs) { unordered_map<int, unordered_set<int>> mapisetAdj;//degree 等于set的大小 int iRoot = 0, iN = 0, iRet = 1; for(auto iter: pairs) { mapisetAdj[iter[0]].emplace(iter[1]); mapisetAdj[iter[1]].emplace(iter[0]); } iN = mapisetAdj.size(); for(auto iter: mapisetAdj) { if(iter.second.size() == iN - 1) { iRoot = iter.first; } } if(!iRoot) return 0; for(auto iter: mapisetAdj) { if(iter.first == iRoot) continue; int iParent = 0, iParentDegree = INT_MAX; for(auto iter2: iter.second) { if(iParentDegree > mapisetAdj[iter2].size() && mapisetAdj[iter2].size() >= iter.second.size()) { iParent = iter2; iParentDegree = mapisetAdj[iter2].size(); } } if(!iParent) return 0; for(auto iter2: iter.second) { if (iter2 == iParent) continue; if(!mapisetAdj[iParent].count(iter2)) return 0; } if(iParentDegree == iter.second.size()) { iRet = 2; } } return iRet; } };
运行结果