LeetCode 2581.统计可能的树根数目:换根DP(树形DP)

news2024/9/19 10:47:16

【LetMeFly】2581.统计可能的树根数目:换根DP(树形DP)

力扣题目链接:https://leetcode.cn/problems/count-number-of-possible-root-nodes/

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

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

  • 选择两个 不相等 的整数 u 和 v ,且树中必须存在边 [u, v] 。
  • Bob 猜测树中 u 是 v 的 父节点 。

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 个正确的猜测。

 

提示:

  • edges.length == n - 1
  • 2 <= n <= 105
  • 1 <= guesses.length <= 105
  • 0 <= ai, bi, uj, vj <= n - 1
  • ai != bi
  • uj != vj
  • edges 表示一棵有效的树。
  • guesses[j] 是树中的一条边。
  • guesses 是唯一的。
  • 0 <= k <= guesses.length

方法一:换根DP(树形DP)

首先我们可以把所有的猜想都存入哈希表中,以便对于某条边,能快速知道其是否有被猜过。

由于节点范围是 1 0 5 10^5 105,因此可以将 父节点 × 1 0 6 + 子节点 父节点 \times 10^6 + 子节点 父节点×106+子节点作为哈希表的键值。(注意可能会超32位整数)

假如只问“0”为根的话猜中次数是否 ≥ k \geq k k,那么我们只需要从 0 0 0开始对树进行深度优先搜索:

搜索过程中统计边被猜中的次数(借助哈希表可以在 O ( 1 ) O(1) O(1)时间内完成一次查询),搜索结束后判断是否 ≥ k \geq k k

现在要问“各个节点”为根的话猜中次数。怎么办?在原有结果的基础上再DP一次即可:

假设在现有的基础上,xy的父节点。此时有cnt个猜中的边。若把y变成x的父节点呢?

来自LeetCode官方题解的“树换根图”

变化的只有xy之间的一条边。

若有猜(x, y),则猜中次数 c n t − 1 cnt-1 cnt1;若有猜(y, x),则猜中次数 c n t + 1 cnt+1 cnt+1

DP过程中(其实就是沿边走的过程)不断将父子关系对调,并统计 c n t ≥ k cnt\geq k cntk的个数即为答案。

  • 时间复杂度 O ( N + M ) O(N + M) O(N+M),其中 N N N是树的节点个数, M = l e n ( g u e s s e s ) M=len(guesses) M=len(guesses)
  • 空间复杂度 O ( N + M ) O(N+M) O(N+M)

AC代码

C++
typedef long long ll;
class Solution {
private:
    int cnt;  // 以0为根时答对的数目
    int ans;
    int k;
    vector<vector<int>> graph;
    unordered_set<ll> se;


    void dfs(int thisNode, int lastNode=-1) {
        for (int nextNode : graph[thisNode]) {
            if (nextNode == lastNode) {
                continue;
            }
            if (se.count((ll)thisNode * 1000000 + nextNode)) {
                cnt++;
            }
            dfs(nextNode, thisNode);
        }
    }

    void change(int thisNode, int lastNode, int cnt) {
        int cnt_bak = cnt;
        for (int nextNode : graph[thisNode]) {
            if (nextNode == lastNode) {
                continue;
            }
            if (se.count((ll)thisNode * 1000000 + nextNode)) {
                cnt--;
            }
            if (se.count((ll)nextNode * 1000000 + thisNode)) {
                cnt++;
            }
            ans += cnt >= k;
            change(nextNode, thisNode, cnt);
            cnt = cnt_bak;
        }
    }
public:
    int rootCount(vector<vector<int>>& edges, vector<vector<int>>& guesses, int k) {
        graph.resize(edges.size() + 1);
        for (vector<int>& edge : edges) {
            graph[edge[0]].push_back(edge[1]);
            graph[edge[1]].push_back(edge[0]);
        }
        for (vector<int>& guess : guesses) {
            se.insert((ll)guess[0] * 1000000 + guess[1]);
        }
        cnt = 0;
        this->k = k;
        dfs(0);
        ans = cnt >= k;
        change(0, -1, cnt);
        return ans;
    }
};
Python
from typing import List

class Solution:  # AC,100.00%,92.59%
    def dfs(self, thisNode: int, lastNode: int) -> None:
        for nextNode in self.graph[thisNode]:
            if nextNode == lastNode:
                continue
            if (thisNode * 1000000 + nextNode) in self.se:
                self.cnt += 1
            self.dfs(nextNode, thisNode)
    
    def change(self, thisNode: int, lastNode: int, cnt: int) -> None:
        cnt_bak = cnt
        for nextNode in self.graph[thisNode]:
            if nextNode == lastNode:
                continue
            if (thisNode * 1000000 + nextNode) in self.se:
                cnt -= 1
            if (nextNode * 1000000 + thisNode) in self.se:
                cnt += 1
            self.ans += cnt >= self.k
            self.change(nextNode, thisNode, cnt)
            cnt = cnt_bak            

    def rootCount(self, edges: List[List[int]], guesses: List[List[int]], k: int) -> int:
        self.graph = [[] for _ in range(len(edges) + 1)]
        for x, y in edges:
            self.graph[x].append(y)
            self.graph[y].append(x)
        self.se = set()
        for x, y in guesses:
            self.se.add(x * 1000000 + y)
        self.cnt = 0
        self.dfs(0, -1)
        self.k = k
        self.ans = 1 if self.cnt >= k else 0
        self.change(0, -1, self.cnt)
        return self.ans

同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/136372137

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1480791.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

文件基础和文件fd

文章目录 预备知识C语言的文件接口系统调用文件fd 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 点击跳转到网站。 预备知识 我们平时说文件就是说文件里…

园区停车管理系统的设计与实现

** &#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;** 一 、设计说明 1.1 选题…

第十四篇【传奇开心果系列】Python的文本和语音相互转换库技术点案例示例:深度解读Azure Cognitive Services个性化推荐系统

传奇开心果博文系列 系列博文目录Python的文本和语音相互转换库技术点案例示例系列 博文目录前言一、个性化推荐系统介绍和关键功能以及优势解说二、雏形示例代码三、个性化推荐示例代码四、实时推荐示例代码五、多种推荐算法示例代码六、易于集成示例代码七、数据安全和隐私保…

minio多版本

minio的多版本是怎么实现的 1、界面上传3次1M文件&#xff0c;可以显示3个版本的 2、在文件名1M目录下会有3个uuid为名的目录 3、其中的xl.meta文件可以使用xl-meta工具解析&#xff0c;这里会记录详细的版本信息 {"Versions": [{"Header": {"Flag…

快速下载Huggingface的大语言模型

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Huggingface是什么&#xff1f;二、基于官方huggingface-cli下载&#xff08;基础&#xff0c;断线风险&#xff09;1.安装hf下载环境2.配置环境变量3.注册…

Container killed on request. Exit code is 143

Bug信息 WARN YarnAllocator: Container marked as failed: container_e33_1480922439133_0845_02_000002 on host: hdp4. Exit status: 143. Diagnostics: Container killed on request. Exit code is 143 Container exited with a non-zero exit code 143 Killed by externa…

css 面试 px,rem,em 区别

一、px是决定单位&#xff0c;一旦设置了就无法因为适应页面大小而改变。 二、em和rem 是相对长度单位&#xff0c; 相对于px更具有灵活性&#xff0c;更适用于响应式布局。 三、em是相对于其父元素来设置字体大小的&#xff0c;一般都是以<body>的“font-size”为基准…

Java核心-异常处理

上一次学完了Java的核心类与API&#xff0c;这次来学习异常处理。我们都知道&#xff0c;Java语言具有健壮性和安全性&#xff0c;而异常处理机制就是其重要保证。如下 一、类型 错误(Error)和异常(Exception)。这里只讨论 Exception 类型的异常处理。 1、错误(Error) Err…

浏览器卡顿解决办法 —— DNS设置

1.Windows - 设置 2.网络和Internet 3.以太网 - 更改适配器选项 4.点击你现在用的网络 (WLAN或以太网)&#xff0c;右键属性 5.双击IPv4协议&#xff0c;DNS地址首选114.114.114.114 南京信风网络科技有限公司&#xff0c;成立于2000年&#xff0c;是一家位于中国南京的高…

LeetCode215.数组中的第K个最大元素

题目 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 输入: [3,2,1,5,6,4], …

基于springboot + vue实现的前后端分离-在线旅游网站系统(项目 + 论文)

项目介绍 本旅游网站系统采用的数据库是MYSQL &#xff0c;使用 JSP 技术开发&#xff0c;在设计过程中&#xff0c;充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。 技术选型 后端: SpringBoot Mybatis 数据库 : MyS…

大模型日报|今日必读的6篇大模型论文

大家好&#xff0c;今日必读的大模型论文来啦&#xff01; 1.中科院、国科大新研究&#xff1a;进行自我感知、更接近人类的AI “机器能思考吗&#xff1f;”这个问题和评估机器是否能达到人类智能水平的图灵测试&#xff0c;是人工智能&#xff08;AI&#xff09;的核心问题…

Stable Diffusion 模型分享:Realistic Stock Photo(真实的库存照片)

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八 下载地址 模型介绍 条目内容类型大模型基础模型SDXL 1.0来源CIVITAI作者PromptSharingSamaritan文件名称reali…

java 获取package下的所有类名

1、获取指定包的路劲 2、根据路劲获取所有实体类的.class文件 3、我们使用ClassLoader来获取资源的URL&#xff0c;然后根据URL获取对应的文件夹。最后&#xff0c;我们使用过滤器来筛选出所有以".class"结尾的文件 获取entity包下所有的实体进行映射 1.包的路劲…

android程序员面试笔试宝典,Android开发社招面试总结

部分面试常问的面试专题 一、Java篇 1.多线程并发&#xff1b; sleep 和 wait 区别join 的用法线程同步&#xff1a;synchronized 关键字等线程通信线程池手写死锁 2.Java 中的引用方式&#xff0c;及各自的使用场景 3.HashMap 的源码 4.GC(垃圾回收)是什么&#xff1f;如何…

浅谈 Linux 网络编程 - Server 端模型、sockaddr、sockaddr_in 结构体

文章目录 前言前置知识Server 端核心模型 【重点】相关函数 【重点】socket 函数bind 函数listen 函数accept 函数close 函数 sockaddr 数据结构 【重点】 前言 本文主要是对 Linux 网络编程中&#xff0c;Server 端的模型、相关函数 以及 sockaddr、sockaddr_in 结构体做介绍…

用node写后端环境运行时报错Port 3000 is already in use

解决方法:关闭之前运行的3000端口,操作如下 1.WindowR输入cmd确定,打开命令面板 2.查看本机端口详情 netstat -ano|findstr "3000" 3.清除3000端口 taskkill -pid 41640 -f 最后再重新npm start即可,这里要看你自己项目中package.joson的启动命令是什…

VBA_MF系列技术资料1-390

MF系列VBA技术资料1-390 为了让广大学员在VBA编程中有切实可行的思路及有效的提高自己的编程技巧&#xff0c;我参考大量的资料&#xff0c;并结合自己的经验总结了这份MF系列VBA技术综合资料&#xff0c;而且开放源码&#xff08;MF04除外&#xff09;&#xff0c;其中MF01-0…

阿里云能处!2024年ta真降价呀!附服务器优惠价格表

阿里云能处&#xff0c;关键时刻ta真降价啊&#xff01;2024新年伊始阿里云带头降价了&#xff0c;不只是云服务器&#xff0c;云数据库和存储产品都降价&#xff0c;阿里云新老用户均可购买99元服务器、199元服务器&#xff0c;续费不涨价&#xff0c;阿里云百科aliyunbaike.c…

新闻网站封锁AI爬虫 AI与新闻媒体博弈继续

随着ChatGPT等新兴AI模型的兴起&#xff0c;它们所依赖的网络爬虫正面临来自全球主流新闻网站的大规模封锁。Richard Fletcher博士团队对十个国家主流新闻网站的统计发现&#xff0c;到2023年底&#xff0c;48%的网站屏蔽了OpenAI的爬虫&#xff0c;24%屏蔽了Google的爬虫。那么…