列表

详情


6314. 统计可能的树根数目

Alice 有一棵 n 个节点的树,节点编号为 0n - 1 。树用一个长度为 n - 1 的二维整数数组 edges 表示,其中 edges[i] = [ai, bi] ,表示树中节点 aibi 之间有一条边。

Alice 想要 Bob 找到这棵树的根。她允许 Bob 对这棵树进行若干次 猜测 。每一次猜测,Bob 做如下事情:

Bob 的猜测用二维整数数组 guesses 表示,其中 guesses[j] = [uj, vj] 表示 Bob 猜 uj 是 vj 的父节点。

Alice 非常懒,她不想逐个回答 Bob 的猜测,只告诉 Bob 这些猜测里面 至少 有 k 个猜测的结果为 true 。

给你二维整数数组 edges ,Bob 的所有猜测和整数 k ,请你返回可能成为树根的 节点数目 。如果没有这样的树,则返回 0

 

示例 1:

输入:edges = [[0,1],[1,2],[1,3],[4,2]], guesses = [[1,3],[0,1],[1,0],[2,4]], k = 3
输出:3
解释:
根为节点 0 ,正确的猜测为 [1,3], [0,1], [2,4]
根为节点 1 ,正确的猜测为 [1,3], [1,0], [2,4]
根为节点 2 ,正确的猜测为 [1,3], [1,0], [2,4]
根为节点 3 ,正确的猜测为 [1,0], [2,4]
根为节点 4 ,正确的猜测为 [1,3], [1,0]
节点 0 ,1 或 2 为根时,可以得到 3 个正确的猜测。

示例 2:

输入:edges = [[0,1],[1,2],[2,3],[3,4]], guesses = [[1,0],[3,4],[2,1],[3,2]], k = 1
输出:5
解释:
根为节点 0 ,正确的猜测为 [3,4]
根为节点 1 ,正确的猜测为 [1,0], [3,4]
根为节点 2 ,正确的猜测为 [1,0], [2,1], [3,4]
根为节点 3 ,正确的猜测为 [1,0], [2,1], [3,2], [3,4]
根为节点 4 ,正确的猜测为 [1,0], [2,1], [3,2]
任何节点为根,都至少有 1 个正确的猜测。

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int rootCount(vector<vector<int>>& edges, vector<vector<int>>& guesses, int k) { } };

php 解法, 执行用时: 661 ms, 内存消耗: 127.6 MB, 提交时间: 2024-02-29 09:37:56

class Solution
{
    /**
     * @param Integer[][] $edges
     * @param Integer[][] $guesses
     * @param Integer $k
     * @return Integer
     */
    function rootCount($edges, $guesses, $k)
    {
        $n=count($edges)+1;
        $e=array_pad([],$n,[]);
        foreach ($edges as $v){
            $e[$v[0]][]=$v[1];
            $e[$v[1]][]=$v[0];
        }
        $g=[];
        foreach ($guesses as $v){
            if (!key_exists($v[0],$g))$g[$v[0]]=[];
            $g[$v[0]][$v[1]]=true;
        }
        $cnt0=0;
        $ans=0;
        $q=new SplDoublyLinkedList();
        $q->push(0);
        $vis=array_pad([],$n,false);
        while (!$q->isEmpty()){
            $s=$q->count();
            while ($s-->0){
                $x=$q->shift();
                $vis[$x]=true;
                foreach ($e[$x] as $y){
                    if (!$vis[$y]){
                        if (key_exists($x,$g)&&key_exists($y,$g[$x]))$cnt0++;
                        $q->push($y);
                    }
                }
            }
        }
        $q->push(0);
        $p=new SplDoublyLinkedList();
        $p->push($cnt0);
        $vis=array_pad([],$n,false);
        while (!$q->isEmpty()){
            $s=$q->count();
            while ($s-->0){
                $x=$q->shift();
                $cnt=$p->shift();
                if($cnt>=$k)$ans++;
                $vis[$x]=true;
                foreach ($e[$x] as $y){
                    if (!$vis[$y]){
                        $u=$cnt;
                        if(key_exists($x,$g)&&key_exists($y,$g[$x]))$u--;
                        if(key_exists($y,$g)&&key_exists($x,$g[$y]))$u++;
                        $p->push($u);
                        $q->push($y);
                    }
                }
            }
        }
        return $ans;
    }
}

cpp 解法, 执行用时: 496 ms, 内存消耗: 230.8 MB, 提交时间: 2023-04-02 12:30:18

class Solution {
public:
    int rootCount(vector<vector<int>> &edges, vector<vector<int>> &guesses, int k) {
        vector<vector<int>> g(edges.size() + 1);
        for (auto &e : edges) {
            int x = e[0], y = e[1];
            g[x].push_back(y);
            g[y].push_back(x); // 建图
        }

        unordered_set<long> s;
        for (auto &e : guesses) // guesses 转成哈希表
            s.insert((long) e[0] << 32 | e[1]); // 两个 4 字节数压缩成一个 8 字节数

        int ans = 0, cnt0 = 0;
        function<void(int, int)> dfs = [&](int x, int fa) {
            for (int y : g[x])
                if (y != fa) {
                    cnt0 += s.count((long) x << 32 | y); // 以 0 为根时,猜对了
                    dfs(y, x);
                }
        };
        dfs(0, -1);

        function<void(int, int, int)> reroot = [&](int x, int fa, int cnt) {
            ans += cnt >= k; // 此时 cnt 就是以 x 为根时的猜对次数
            for (int y : g[x])
                if (y != fa) {
                    reroot(y, x, cnt
                                 - s.count((long) x << 32 | y) // 原来是对的,现在错了
                                 + s.count((long) y << 32 | x)); // 原来是错的,现在对了
                }
        };
        reroot(0, -1, cnt0);
        return ans;
    }
};

golang 解法, 执行用时: 316 ms, 内存消耗: 58.1 MB, 提交时间: 2023-04-02 12:30:01

func rootCount(edges [][]int, guesses [][]int, k int) (ans int) {
	g := make([][]int, len(edges)+1)
	for _, e := range edges {
		v, w := e[0], e[1]
		g[v] = append(g[v], w)
		g[w] = append(g[w], v) // 建图
	}

	type pair struct{ x, y int }
	s := make(map[pair]int, len(guesses))
	for _, p := range guesses { // guesses 转成哈希表
		s[pair{p[0], p[1]}] = 1
	}

	cnt0 := 0
	var dfs func(int, int)
	dfs = func(x, fa int) {
		for _, y := range g[x] {
			if y != fa {
				if s[pair{x, y}] == 1 { // 以 0 为根时,猜对了
					cnt0++
				}
				dfs(y, x)
			}
		}
	}
	dfs(0, -1)

	var reroot func(int, int, int)
	reroot = func(x, fa, cnt int) {
		if cnt >= k { // 此时 cnt 就是以 x 为根时的猜对次数
			ans++
		}
		for _, y := range g[x] {
			if y != fa {
				reroot(y, x, cnt-s[pair{x, y}]+s[pair{y, x}])
			}
		}
	}
	reroot(0, -1, cnt0)
	return
}

java 解法, 执行用时: 200 ms, 内存消耗: 120.6 MB, 提交时间: 2023-04-02 12:29:49

class Solution {
    private List<Integer>[] g;
    private Set<Long> s = new HashSet<>();
    private int k, ans, cnt0;

    public int rootCount(int[][] edges, int[][] guesses, int k) {
        this.k = k;
        g = new ArrayList[edges.length + 1];
        Arrays.setAll(g, e -> new ArrayList<>());
        for (var e : edges) {
            int x = e[0], y = e[1];
            g[x].add(y);
            g[y].add(x); // 建图
        }

        for (var e : guesses) // guesses 转成哈希表
            s.add((long) e[0] << 32 | e[1]); // 两个 4 字节数压缩成一个 8 字节数

        dfs(0, -1);
        reroot(0, -1, cnt0);
        return ans;
    }

    private void dfs(int x, int fa) {
        for (var y : g[x])
            if (y != fa) {
                if (s.contains((long) x << 32 | y)) // 以 0 为根时,猜对了
                    ++cnt0;
                dfs(y, x);
            }
    }

    private void reroot(int x, int fa, int cnt) {
        if (cnt >= k) ++ans; // 此时 cnt 就是以 x 为根时的猜对次数
        for (var y : g[x])
            if (y != fa) {
                int c = cnt;
                if (s.contains((long) x << 32 | y)) --c; // 原来是对的,现在错了
                if (s.contains((long) y << 32 | x)) ++c; // 原来是错的,现在对了
                reroot(y, x, c);
            }
    }
}

python3 解法, 执行用时: 500 ms, 内存消耗: 182.5 MB, 提交时间: 2023-04-02 12:29:36

class Solution:
    def rootCount(self, edges: List[List[int]], guesses: List[List[int]], k: int) -> int:
        g = [[] for _ in range(len(edges) + 1)]
        for x, y in edges:
            g[x].append(y)
            g[y].append(x)  # 建图

        s = {(x, y) for x, y in guesses}  # guesses 转成哈希表 s

        ans = cnt0 = 0
        def dfs(x: int, fa: int) -> None:
            nonlocal cnt0
            for y in g[x]:
                if y != fa:
                    cnt0 += (x, y) in s  # 以 0 为根时,猜对了
                    dfs(y, x)
        dfs(0, -1)

        def reroot(x: int, fa: int, cnt: int) -> None:
            nonlocal ans
            ans += cnt >= k  # 此时 cnt 就是以 x 为根时的猜对次数
            for y in g[x]:
                if y != fa:
                    reroot(y, x, cnt - ((x, y) in s) + ((y, x) in s))
        reroot(0, -1, cnt0)
        return ans

上一题