10.31 每日一题

64 阅读2分钟

每日一题

2003. 每棵子树内缺失的最小基因值(hard)

每棵子树内缺失的最小基因值

主要思路是寻找两种树, 一类是子树基因包含1的结点(那么ans其子树的父节点的缺失的基因值为1); 另外一类是子树基因不包含1的结点, 那么需要去遍历其子树的所有基因值。

class Solution {
    // 寻找的是 每个节点为根的子树中, 权重在 [1, n+1]范围内的最小缺失值, 而不是nums中的缺失值
    // 把结点分成两类, 一类是子树基因包含值为1的节点, 一类是子树基因不包含值为1(遍历其子树的所有基因值)
    List<List<Integer>> children; // 子节点序列
    Set<Integer> genSet; //基因值序列
    // 结点值[0,n-1], 基因值
    public int[] smallestMissingValueSubtree(int[] parents, int[] nums) {
        int n = parents.length;
        children = new ArrayList<>();
        for(int i = 0; i<n; i++){
            children.add(new ArrayList<>()); // 生成每个节点的子节点序列
        }
        int getOnePathNode = nums[0] == 1 ? 0 : -1;
        for(int i = 1; i<n; i++){
            children.get(parents[i]).add(i); // 增加子节点
            if(nums[i] == 1) getOnePathNode = i; // 找到基因值为1的节点
        }
        int[] ans = new int[n];
        Arrays.fill(ans, 1); // 初始化, 值全为1
        int lastNode = -1; // 上一个处理的节点, 其子树无需处理
        int missVal = 2; // 基因值为1节点 在路径上的节点, 最小缺失值从2开始找
        genSet = new HashSet<>();
        while(getOnePathNode != -1){
            dfs(getOnePathNode, lastNode, nums); // 搜索以getOnePathNode为根的
            while(genSet.contains(missVal)) missVal++;
            ans[getOnePathNode] = missVal; // 当前节点的缺失值 ([1,n])
            lastNode = getOnePathNode; // lastNode 为上一个搜索过的结点, 其子树已经搜索过
            getOnePathNode = parents[getOnePathNode]; // (递归弹栈) 向上去遍历, 更新父节点缺失的基因值
        }
        return ans;
    }
    void dfs(int node, int getOnePathNode, int[] nums){ // 深搜每个子树
        genSet.add(nums[node]); // 添加子节点的基因值
        for(int child: children.get(node)){
            if(child == getOnePathNode) continue; // 说明已经搜索过, continue 跳过当前循环
            dfs(child, getOnePathNode, nums); // 搜索其子树
        }
    }
}

此解法是参考LeetCode上公开的解法, 希望大佬们能够批评指正, 谢谢!