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

【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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot实现图书馆管理系统项目【项目源码+论文说明】

基于springboot实现图书馆管理系统演示 摘要 电脑的出现是一个时代的进步&#xff0c;不仅仅帮助人们解决了一些数学上的难题&#xff0c;如今电脑的出现&#xff0c;更加方便了人们在工作和生活中对于一些事物的处理。应用的越来越广泛&#xff0c;通过互联网我们可以更方便地…

C++用临时对象构造新对象

C用临时对象构造新对象 //用临时对象构造同类型的新对象&#xff0c;该临时对象不产生&#xff1b; // 直接用生成临时对象的方法构造新对象&#xff0c;这是编译器对代码的优化&#xff0c;效率更高 #include<iostream> using namespace std; class MyClass { public:…

2024最新性能测试面试题(带答案)

一、性能测试开展过程&#xff1a; 答&#xff1a;第一步&#xff1a;找产品沟通哪些接口需要压测&#xff0c;需要达到什么样的预期值(TPS和响应时间) 第二步&#xff1a;编写测试计划&#xff0c;人员、时间周期、工具 第三步&#xff1a;环境搭建 第四步&#xff1a;造数…

若依前后端分离版本-自动生成代码

听说若依挺好用的&#xff0c;所以来学习一下。 1.下载项目&#xff0c;配置redis,配置mysql,安装npm&#xff08;版本一定要低于16&#xff09; 2.执行sql脚本数据库相关信息 3.启动后端ruoyi-admin的ruoyiApplication 4启动前端 选择terminal 进入ruoyi-ui&#xff0c;执…

数据结构从入门到精通——算法的时间复杂度和空间复杂度

算法的时间复杂度和空间复杂度 前言一、算法效率1.1 如何衡量一个算法的好坏1.2 算法的复杂度 二、时间复杂度2.1 时间复杂度的概念2.2 大O的渐进表示法2.3常见时间复杂度计算举例2.4等差数列计算公式2.5等比数列计算方法 三、空间复杂度四、 常见复杂度对比五、 复杂度的oj练习…

今日arXiv最热大模型论文:点击即可播放!港中文发布大模型写歌神器!

一首歌&#xff0c;包含作词作曲两个部分。擅长作词or作曲就已经很牛了。比如方文山是周杰伦的御用作词人&#xff0c;而周杰伦写过很多耳熟能详的曲子。而兼具作词作曲才华的全能创作人却是难得一见。 最近港中文发布了一款歌曲创作大模型SongComposer&#xff0c;作词作曲都…

R语言安装和简单入门HelloWorld用法

R语言安装和简单入门HelloWorld用法 #R语言安装地址 https://www.r-project.org/ click->CRAN mirror->选择China下列表&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/CRAN/ 选择Download R for Windows 选择base Download R-4.3.2 for Windows 下载文件R-4.3.2-…

SQL-Labs靶场“26-28”关通关教程

君衍. 一、二十六关 基于GET过滤空格以及注释报错注入1、源码分析2、绕过思路3、updatexml报错注入 二、二十六a关 基于GET过滤空格注释字符型注入1、源码分析2、绕过思路3、时间盲注 三、二十七关 基于union及select的过滤单引号注入1、源码分析2、绕过思路3、联合查询注入4、…

springcloud alibaba组件简介

一、Nacos 服务注册中心/统一配置中心 1、介绍 Nacos是一个配置中心&#xff0c;也是一个服务注册与发现中心。 1.1、配置中心的好处&#xff1a; &#xff08;1&#xff09;配置数据脱敏 &#xff08;2&#xff09;防止出错&#xff0c;方便管理 &#xff08;3&#xff…

精品ssm的社区团购系统购物商城小程序

《[含文档PPT源码等]精品基于ssm的社区团购系统[包运行成功]》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; Java——涉及技术&#xff1a; 前端使用技术&#xff1a;HTML5,CSS3、Jav…

从前端JS逆向到发现后端越权漏洞的渗透测试之旅

前言 本篇文章首发先知社区&#xff0c;作者为本公众号。 前端分析 首先搜索请求接口&#xff0c;未发现关键加密点 根据请求参数进行搜索 在js文件中找到aes加密key、iv eval(function(p, a, c, k, e, r) { e function(c) { return c.toString(36) } ; if…

什么是MTU(Maximum Transmission Unit)?

热门IT课程【视频教程】-华为/思科/红帽/oraclehttps://xmws-it.blog.csdn.net/article/details/117297837?spm1001.2014.3001.5502 最大传输单元MTU&#xff08;Maximum Transmission Unit&#xff0c;MTU&#xff09;&#xff0c;是指网络能够传输的最大数据包大小&#x…

禁止涉密电脑插U盘

某国家机关在日常工作中发现&#xff0c;一台涉密电脑受到了不明攻击&#xff0c;大量机密文件被非法访问和复制。 经过调查&#xff0c;原来是一名工作人员在不知情的情况下&#xff0c;将感染病毒的U盘插入涉密电脑&#xff0c;导致机密数据被窃取。 事件发生后&#xff0c…

【软考】UML中的图之通信图

目录 1. 说明2. 图示3. 特性4. 例题4.1 例题1 1. 说明 1.通信图强调收发消息的对象的结构组织2.早期版本叫做协作图3.通信图强调参加交互的对象和组织4.首先将参加交互的对象作为图的顶点&#xff0c;然后把连接这些对象的链表示为图的弧&#xff0c;最后用对象发送和接收的消…

【Mars3d】进行水平测量measure.area({的时候,会被模型遮挡的处理方法

问题&#xff1a; 1.thing/analysis/measure 水平面积 measure.area({ 在模型上测量的时候会被遮挡 2. 通过 addHeight:10000,增加高度也不可以实现这种被遮挡的效果&#xff0c;都增加到10000了&#xff0c;还是会被遮挡 export function measureArea() { measure.area({ s…

动态规划(算法竞赛、蓝桥杯)--单调队列滑动窗口与连续子序列的最大和

1、B站视频链接&#xff1a;E11【模板】单调队列 滑动窗口最值_哔哩哔哩_bilibili 题目链接&#xff1a;滑动窗口 /【模板】单调队列 - 洛谷 #include <bits/stdc.h> using namespace std; const int N1000010; int a[N],q[N];//q存的是元素的下标 int main(){int n,k;…

数据结构题目①——数组

前言 本篇文章为博主进行代码随想录——数组练习后的总结会涉及到每一道题目的详细的思路整理&#xff0c;以及本人的易错点&#xff0c;希望对大家有所帮助 数组介绍&#xff1a; 数组在C语言中就已经有所涉及&#xff0c;它是一个最基础的数据结构&#xff0c;而在数据结构中…

从零学算法289

289.根据 百度百科 &#xff0c; 生命游戏 &#xff0c;简称为 生命 &#xff0c;是英国数学家约翰何顿康威在 1970 年发明的细胞自动机。 给定一个包含 m n 个格子的面板&#xff0c;每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态&#xff1a; 1 即为 活细胞 …

接上Promise()对象处理回调地狱:怎么用.then()?什么是Async、Await?

上一篇基于JavaScript基础的异步、同步操作&#xff0c;promise、.then()-CSDN博客讲了【啥是异步操作、同步操作&#xff1f;】然后简单讲了回调函数是啥、Promise()对象是啥、.then()函数是啥&#xff0c;这一篇讲讲promise()对象到底怎么配合.then()函数解决回调地狱&#x…

学习和工作的投入产出比(节选)

人工智能统领全文 推荐包含关于投入、产出、过剩、市场关注、案例、结果和避雷等主题的信息&#xff1a; 投入与产出&#xff1a; 投入和产出都有直接和间接两类常见形式。常见的四种组合是&#xff1a;直接投入、直接产出、间接投入、间接产出。 过剩&#xff1a; 过剩是一个重…