【力扣每日一题】2023.9.21 收集树中金币

2023-09-21 11:18:13

目录

题目:

示例:

分析:

代码:


题目:

示例:

分析:

题目给我们一棵树,不过这棵树不是普通的树,而是无向无根树。给我们一个二维数组表示节点之间的连接关系,以及一个一维数组表示每个节点是否有金币。

我们可以从任何一个节点出发,并且可以收集距离两格的节点的金币,每次可以移动到相邻的节点。问我们要收集完所有的金币并且最终要回到起点,最少需要移动几次。

首先,题目说了这是一棵树,所以是不存在环的,两个节点之间连通的路径只会有唯一的一条。

因此我们不管选择哪一个节点当起点,都是可以到达任意一个节点的。

我们需要获取所有的金币,那么如果一个节点没有金币,并且这个节点是叶子节点,那么我们是不是可以将这个节点直接从树中移除,因为我们根本不需要走到这个节点。

我们把能删除的节点都删除了,是不是就说明剩下的节点都是我们需要走到或是收集金币的节点。

如果我们把整棵树剪到只剩下我们必须要走到的节点之后,答案就剩下节点数-1再乘2了。

为什么呢?

题目要求我们必须在收集完金币之后再返回原点,我们有n个必须到达的节点,由于这是树,是没有环的,因此节点之间的连线一共是n-1条。一来一回每个线段要走两次,所以答案是(n-1)*2

问题就变成了我们怎么把树的节点剪到只剩下我们必须要走的节点。

首先,没有金币的叶子节点我们是可以先删除的。判断依据也简单,如果一个节点没有金币,并且和这个节点连接的其他节点只有一个,那么它就是没有金币的叶子节点,可以把它删除。并且删除某个节点之后可能会诞生出新的无金币叶子节点,因此我们删除节点之后还需要判断一下与这个节点连接的节点是否也是无金币叶子节点,也就是延伸性地删除节点。

那么怎么删除呢,我们可没有构建出树来。

我们其实不需要真的删除。我们之前分析过了,答案就是剪枝后的节点数减1再乘2。我们可以当成一开始的树就是我们剪枝后的树,把答案初始化成总的节点数减1再乘2。每次我们删除一个节点就等于是移除了一个线段,把答案减2即可,这样就当成是删除一个节点了。

初步移除了没有金币的叶子节点之后剩下的节点就是我们要达到的节点或者是要收集金币的节点了。

我们把剩下的树看成是图,那么图边缘一圈的节点一定都是有金币的。

我们收集金币的时候可以距离金币节点两格,因此我们可以再一次把图的外围两层节点删除,不过删除是有条件的,最外层的叶子节点可以直接删除,不过第二层的节点我们得判断删除了外层节点后,第二层的节点是不是叶子节点,如果是我们才可以删除。

最终我们每次删除节点之后,都将答案-2,最终就是要返回出去的答案了。

不过最后还有一个问题,那就是如果整个树都是可以移除的,那么根据我们刚才说的每删除一个节点就把答案-2,而我们答案初始化是总的节点数减1再乘2,这样答案就变成了-2,因此最后我们做个判断,如果答案小于0,我们就返回0,反之就正常返回求出的答案。

代码:

class Solution {
public:
    unordered_map<int,vector<int>>pic;  //记录节点连接图
    unordered_map<int,int>rel;          //记录每个节点的邻接数量关系
    int collectTheCoins(vector<int>& coins, vector<vector<int>>& edges) {
        int n=coins.size();
        int res=2*(n-1);    //答案初始化成图中线段数乘2,表示每个线段都要走两边
        //建图
        for(auto& edge:edges){
            if(pic.find(edge[0])==pic.end()) pic[edge[0]]=vector<int>(0);
            if(pic.find(edge[1])==pic.end()) pic[edge[1]]=vector<int>(0);
            pic[edge[0]].push_back(edge[1]);
            pic[edge[1]].push_back(edge[0]);
            rel[edge[0]]++;rel[edge[1]]++;
        }
        queue<int> q;
        
        //删除无金币的叶子节点(可延伸)
        for(int i=0;i<n;i++){
            if(coins[i]==0 && rel[i]==1) q.push(i);
        }
        while(!q.empty()){
            res-=2;         //减少一个线段,答案减2,因为默认每个线段走两次.
            int cur=q.front();q.pop();
            for(int i:pic[cur]){
                if(--rel[i]==1&&coins[i]==0) q.push(i);
            }
        }

        //确定到有金币的叶子节点的范围.
        for(int i=0;i<n;i++){
            if(coins[i]==1&&rel[i]==1) q.push(i);
        }
        res-=2*q.size();
        //减少叶子节点,不延伸(因为可以收集距离两格的金币,所以可以在边缘处再缩小一圈)
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int j:pic[x]){
                if(--rel[j]==1) res-=2;
            }
        }

        if(res>0) return res;
        return 0;
    }
};

更多推荐

全能电子地图下载器3.0-下载离线地图瓦片

前言vue项目要部署到局域网内,不使用在线地图,而是离线地图,寻求了很多的解决方案,最终决定使用离线地图瓦片+leaflet.js实现效果!正文首先需要下载正版的软件,目前我实用的是V3.0版本的,可能和之前的有部分差异化,这个也属于正常。一、下载1.有CSDN会员下载渠道:https://download.csdn.

Vue入门--vue的生命周期

一.什么是Vue二.Vue的简介官方网址特点三.前后端的分离重大问题优势4.Vue入门定义一个管理边界​编辑测试结果vue的优势​编辑测试结果5.Vue的生命周期vue的生命周期图​编辑建立一个html测试结果一.什么是VueVue是一种流行的JavaScript前端框架,用于构建用户界面。它被设计为一种渐进式框架,可

CTF —— 网络安全大赛(这不比王者好玩吗?)

前言随着大数据、人工智能的发展,人们步入了新的时代,逐渐走上科技的巅峰。\⚔科技是一把双刃剑,网络安全不容忽视,人们的隐私在大数据面前暴露无遗,账户被盗、资金损失、网络诈骗、隐私泄露,种种迹象表明,随着互联网的发展,网络安全需要引起人们的重视。\互联网安全从其本质上来讲就是互联网上的信息安全。从广义来说,凡是涉及到互联

3.2 Android eBPF程序类型

写在前面为什么要先了解eBPF程序类型?从帮助函数中,我们可能基于内核的eBPF开放API,对eBPF的能力有一个比较细致的认识,但是这并不能让我们从全局,或者更概括的认识eBPF。eBPF程序类型能够更宏观的告诉我们,eBPF能做哪些事情(除网络相关)。一,eBPF程序类型内核中不同事件会触发不同类型的eBPF程序,

什么是Webpack的Tree Shaking?它的作用是什么?

聚沙成塔·每天进步一点点⭐专栏简介⭐Webpack的TreeShaking⭐作用和原理⭐使用TreeShaking⭐写在最后⭐专栏简介前端入门之旅:探索Web开发的奇妙世界欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些

简单 php结合WebUploader实现文件上传功能

WebUploader资源下载http://fex.baidu.com/webuploader/download.htmlWebUploader使用方法http://fex.baidu.com/webuploader/getting-started.htmlphp上传代码<?phpheader('Content-typ

MFC主框架和视类PreCreateWindow()函数学习

在VC++生成的单文档应用程序中,主框架类和视类均具有PreCreateWindow函数;从名字可知,可在此函数中添加一些代码,来控制窗口显示后的效果;并且它有注释说明,ModifytheWindowclassorstylesherebymodifyingtheCREATESTRUCTcs在这里通过修改CREATEST

​Qt for Python 入门¶​

本页重点介绍如何从源代码构建QtforPython,如果你只想安装PySide2。与你需要运行:pippipinstallpyside2有关更多详细信息,请参阅我们的快速入门指南。此外,您可以查看与项目相关的常见问题解答。一般要求¶Python:3.5+和2.7Qt:建议使用5.12+libclang:libclang

Leetcode.486 预测赢家

题目链接Leetcode.486预测赢家mid题目描述给你一个整数数组nums。玩家111和玩家222基于这个数组设计了一个游戏。玩家111和玩家222轮流进行自己的回合,玩家111先手。开始时,两个玩家的初始分值都是000。每一回合,玩家从数组的任意一端取一个数字(即,nums[0]nums[0]nums[0]或nu

掌握ls命令:完整指南、高级用法与常见问题解答 | 理解文件管理的关键工具

文章目录引言1.1关于ls命令1.2ls命令的作用和用途ls命令的基本用法2.1命令格式和语法2.2列出当前目录内容2.3列出指定目录内容常用选项和参数3.1列出详细信息3.2列出隐藏文件3.3按不同方式排序3.4显示文件大小3.5递归列出子目录内容文件类型和权限4.1文件类型的表示4.2权限的表示和解读4.3更改文件

Java基于微信小程序的青少年健康心理科普平台

第一章简介青少年心理健康科普平台为用户提供心理医生咨询服务,系统包括微信小程序端和后台。微信小程序用户可以先进行注册,填写个人的基本信息提交到服务器,服务器把数据保存到数据库。管理员对青少年的信息进行验证后,青少年通过验证后的用户名和密码进行登录,登录之后查看健康知识。心理医生在首页展示,查看心理医生具体信息后,可以进

热文推荐