1. 题意
给定一颗树,求所有子树的最小基因值。
最小基因值定义为,该树的所有节点组成的集合中未出现的最小正整数。
每颗子树内缺失的最小基因值
2. 题解
2.1 启发式合并
直接递归求出左右子树的所有可能值,与根节点进行合并,注意始终是大集合合并小集合。即启发式合并。
- 一个小优化,父节点的最小基因值必定大于等于子节点
class Solution {
public:vector<int> smallestMissingValueSubtree(vector<int>& parents, vector<int>& nums) {int sz = parents.size();vector<int> res(sz, 1);vector<vector<int>> childs(sz);int kNode = -1;for ( int i = 0; i < sz; ++i) {if ( parents[i] >= 0)childs[parents[i]].push_back(i);if ( nums[i] == 1)kNode = i;}vector<int> vis(sz, 0);unordered_set<int> um;function<void(int)> dfs = [&](int rt) {if (vis[rt])return;vis[rt] = 1;um.insert(nums[rt]);for (int v:childs[rt])dfs(v);};int cnt = 1;while ( kNode != -1) {dfs(kNode);while ( um.count(cnt))++cnt;res[kNode] = cnt;kNode = parents[kNode];}return res;}
};
2.2 找出值为1的节点
实际上不难得出,对于所有子节点不包含 1
的树,他们的最小基因值为1
。
而对于以1
为祖先节点的子节点来说,他们的最小基因值也为1
。
只需要考虑值为1
的祖先节点的最小基因值;所以我们可以先找到值为1
的节点,递归求出他的所有
子节点值集合,自底向上求出祖先,我们可以vis
标记这个节点是否被求过来减少重复。
class Solution {
public:vector<int> smallestMissingValueSubtree(vector<int>& parents, vector<int>& nums) {int sz = parents.size();vector<int> res(sz, 1);vector<vector<int>> childs(sz);int kNode = -1;for ( int i = 0; i < sz; ++i) {if ( parents[i] >= 0)childs[parents[i]].push_back(i);if ( nums[i] == 1)kNode = i;}vector<int> vis(sz, 0);unordered_set<int> um;function<void(int)> dfs = [&](int rt) {if (vis[rt])return;vis[rt] = 1;um.insert(nums[rt]);for (int v:childs[rt])dfs(v);};int cnt = 1;while ( kNode != -1) {dfs(kNode);while ( um.count(cnt))++cnt;res[kNode] = cnt;kNode = parents[kNode];}return res;}
};