【Leetcode 每日一题】2920. 收集所有金币可获得的最大积分

news2025/1/24 5:48:06

问题背景

有一棵由 n n n 个节点组成的无向树,以 0 0 0 为根节点,节点编号从 0 0 0 ( n − 1 ) (n - 1) (n1)。给你一个长度为 ( n − 1 ) (n - 1) (n1) 的二维 整数 数组 e d g e s edges edges,其中 e d g e s [ i ] = [ a i , b i ] edges[i] = [a_i, b_i] edges[i]=[ai,bi] 表示在树上的节点 a i a_i ai b i b_i bi 之间存在一条边。另给你一个下标从 0 0 0 开始、长度为 n n n 的数组 c o i n s coins coins 和一个整数 k k k,其中 c o i n s [ i ] coins[i] coins[i] 表示节点 i i i 处的金币数量。
从根节点开始,你必须收集所有金币。要想收集节点上的金币,必须先收集该节点的祖先节点上的金币。
节点 i i i 上的金币可以用下述方法之一进行收集:

  • 收集所有金币,得到共计 ( c o i n s [ i ] − k ) (coins[i] - k) (coins[i]k) 点积分。如果 ( c o i n s [ i ] − k ) (coins[i] - k) (coins[i]k) 是负数,你将会失去 a b s ( c o i n s [ i ] − k ) abs(coins[i] - k) abs(coins[i]k) 点积分。
  • 收集所有金币,得到共计 f l o o r ( c o i n s [ i ] / 2 ) floor(coins[i] / 2) floor(coins[i]/2) 点积分。如果采用这种方法,节点 i i i 子树中所有节点 j j j 的金币数 c o i n s [ j ] coins[j] coins[j] 将会减少至 f l o o r ( c o i n s [ j ] / 2 ) floor(coins[j] / 2) floor(coins[j]/2)
    返回收集 所有 树节点的金币之后可以获得的最大积分。

数据约束

  • n = c o i n s . l e n g t h n = coins.length n=coins.length
  • 2 ≤ n ≤ 1 0 5 2 \le n \le 10 ^ 5 2n105
  • 0 ≤ c o i n s [ i ] ≤ 1 0 4 0 \le coins[i] \le 10 ^ 4 0coins[i]104
  • e d g e s . l e n g t h = n − 1 edges.length = n - 1 edges.length=n1
  • 0 ≤ e d g e s [ i ] [ 0 ] , e d g e s [ i ] [ 1 ] < n 0 \le edges[i][0], edges[i][1] \lt n 0edges[i][0],edges[i][1]<n
  • 0 ≤ k ≤ 1 0 4 0 \le k \le 10 ^ 4 0k104

解题过程

这题比较麻烦的地方在于不好记录除法到底进行了多少次,看了 灵神的题解,才意识到把除法转化成右移,还可以避免边界的处理。
状态转移方程是现成的,也可以比较方便地翻译成递推。

处理树的过程中还需要额外注意一点,递归的时候只能枚举子节点,不能往父节点走,为此需要在方法中多定义一个参数。

具体实现

递归

class Solution {
    public int maximumPoints(int[][] edges, int[] coins, int k) {
        int n = coins.length;
        // 树和图是类似的,用图的手段建立一般树
        List<Integer>[] graph = new ArrayList[n];
        Arrays.setAll(graph, i -> new ArrayList<>());
        for (int[] edge : edges) {
            int x = edge[0];
            int y = edge[1];
            graph[x].add(y);
            graph[y].add(x);
        }
        int[][] memo = new int[n][14];
        // 在每个节点处,零是可能的结果,数组元素要初始化为 -1
        for (int[] row : memo) {
            Arrays.fill(row, -1);
        }
        return dfs(0, 0, -1, memo, graph, coins, k);
    }

    private int dfs (int i, int j, int father, int[][] memo, List<Integer>[] graph, int[] coins, int k) {
        if (memo[i][j] != -1) {
            return memo[i][j];
        }
        int res1 = (coins[i] >> j) - k;
        int res2 = coins[i] >> (j + 1);
        // 遍历所有子节点
        for (int child : graph[i]) {
            // 如果当前枚举到的节点是父节点,那跳过当前轮次
            if (child == father) {
                continue;
            }
            res1 += dfs(child, j, i, memo, graph, coins, k);
            // 如果还能右移,那进一步计算右移的情形
            if (j < 13) {
                res2 += dfs(child, j + 1, i, memo, graph, coins, k);
            }
        }
        // 记录结果并返回
        return memo[i][j] = Math.max(res1, res2);
    }
}

递推

class Solution {
    public int maximumPoints(int[][] edges, int[] coins, int k) {
        // 树和图是类似的,用图的手段建立一般树
        List<Integer>[] graph = new ArrayList[coins.length];
        Arrays.setAll(graph, i -> new ArrayList());
        for (int[] edge : edges) {
            int x = edge[0];
            int y = edge[1];
            graph[x].add(y);
            graph[y].add(x);
        }
        return dfs(0, -1, graph, coins, k)[0];
    }

    private int[] dfs(int x, int father, List<Integer>[] graph, int[] coins, int k) {
        int[] dp = new int[14];
        for (int y : graph[x]) {
            if(y == father) {
                continue;
            }
            // 自底向上,先确定子节点的值
            int[] res = dfs(y, x, graph, coins, k);
            for (int j = 0; j < 14; j++) {
                dp[j] += res[j];
            }
        }
        for (int j = 0; j < 13; j++) {
            dp[j] = Math.max((coins[x] >> j) - k + dp[j], (coins[x] >> (j + 1)) + dp[j + 1]);
        }
        // 如果继续右移结果一定为零,这种情况要单独赋值
        dp[13] += (coins[x] >> 13) - k;
        return dp;
    }
}

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

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

相关文章

谷粒商城——商品服务-三级分类

1.商品服务-三级分类 1.1三级分类介绍 1.2查询三级分类查询-递归树型结构数据获取 1.2.1导入数据pms_catelog.sql到数据表pms_category 1.2.2一次性查出所有分类及子分类 1.2.2.1修改CategoryController.java /*** 查出所有分类以及子分类&#xff0c;以树形结构组装起来*/R…

AviatorScript用法

AviatorScript的介绍&#xff0c;网上有很多&#xff0c;这里就不啰嗦了。这里介绍下传参的用法 应用场景&#xff1a;如果不想频繁的打包升级&#xff0c;而是想只更新某些规则脚本重启服务就可以升级的话&#xff0c;AviatorScript无疑是最佳选择。比如说&#xff0c;今天制…

云计算和服务器

一、云计算概述 ICT是世界电信协会在2001年的全球性会议上提出的综合性概念&#xff0c;ICT分为IT和CT&#xff0c;IT(information technology)信息技术&#xff0c;负责对数据生命周期的管理&#xff1b;CT(communication technology)&#xff0c;负责数据的传输管理。 CT技术…

论文:深度可分离神经网络存内计算处理芯片

引言&#xff1a;SRAM - CIM芯片在处理深度可分离神经网络时面临的挑战 深度可分离卷积&#xff08;Depthwise separable convolution, DSC&#xff09;由逐深度卷积&#xff08;DW&#xff09;和逐点卷积&#xff08;PW)组成&#xff0c;逐深度卷积用于提取空间特征&#xff…

代码随想录刷题day14(1)|(链表篇)142.环形链表 II

目录 一、链表理论基础 二、环形链表思路 1.如何判断有环&#xff1f; 2.如何找出环的入口&#xff1f; 3.其他疑问 三、相关算法题目 四、总结 一、链表理论基础 代码随想录 (programmercarl.com) 二、环形链表思路 1.如何判断有环&#xff1f; 使用快慢指针法&…

运算放大器应用电路设计笔记(六)

6.1输出失调电压发生的原因与计算 6.1.1用噪声增益进行评价 若运算放大器两个输入端接地&#xff0c;则理想运放输出为零&#xff0c;但实际的运放输出不为零&#xff0c;有一定的直流输出电压。这种直流电压称为输出失调电压。发生的原因是&#xff0c;运算放大器内部元件尤…

openresty(nginx)+lua+kafka实现日志搜集系统

今天我们来实现一下快捷的nginx日志搜集系统&#xff0c;主讲的是nginx服务里面的openresty的日志搜集。采用的手段是采用lua做中间桥梁。 一、安装openresty 具体安装步骤在这里《centos7 二进制安装openresty》 二、安装kafka 1、安装Java及配置Java 具体安装步骤在这里《采…

PortSwigger靶场练习---网页 LLM 攻击:间接提示注入

网页 LLM 攻击&#xff1a; Indirect prompt injection 间接提示注入 PortSwigger靶场地址&#xff1a; Dashboard | Web Security Academy - PortSwigger 题目&#xff1a; 官方提示&#xff1a; 发现攻击面 点击实时聊天以访问实验室的聊天功能。 询问LLM它有权访问哪些 AP…

【2024.12】西电英语听说雨课堂期末考试答案

前言 这次的英语听说1和2雨课堂期末是同一张卷子。 26-40为填空题&#xff0c;后面有些话太长了 37. when they are physicial active 38. people could need two times as much water as others do 39. why people have the idea that good health requires eight…

人声检测原理VAD

在机器人的研究中&#xff0c;机器人与人语音交互是一个重要的功能&#xff0c;在语音交互中&#xff0c;人声检测至关重要。不论是在手机中&#xff0c;还是在esp32芯片上&#xff0c;都需要一种简单快捷的方式来检测本地语音&#xff0c;滤掉杂音和噪音。 机器人启动后会一直…

2_高并发内存池_各层级的框架设计及ThreadCache(线程缓存)申请内存设计

一、高并发内存池框架设计 高并发池框架设计&#xff0c;特别是针对内存池的设计&#xff0c;需要充分考虑多线程环境下&#xff1a; 性能问题锁竞争问题内存碎片问题 高并发内存池的整体框架设计旨在提高内存的申请和释放效率&#xff0c;减少锁竞争和内存碎片。 高并发内存…

后端开发基础——JavaWeb(Servlet)

Servlet 关于系统架构 系统架构包括什么形式&#xff1f; C/S架构 B/S架构 C/S架构&#xff1f; Client / Server&#xff08;客户端 / 服务器&#xff09; C/S架构的软件或者说系统有哪些呢&#xff1f; QQ&#xff08;先去腾讯官网下载一个QQ软件&#xff0c;几十MB&…

c++ 与 Matlab 程序的数据比对

文章目录 背景环境数据保存数据加载 背景 ***避免数据精度误差&#xff0c;快速对比变量 *** 环境 c下载 https://github.com/BlueBrain/HighFive 以及hdf5库 在vs 中配置库 数据保存 #include <highfive/highfive.hpp> using namespace HighFive;std::string fil…

Leecode刷题C语言之收集所有金币可获得的最大积分

执行结果:通过 执行用时和内存消耗如下&#xff1a; int dfs(int node, int parent, int f, int* coins, int k, int **children, int *childCount, int **memo) {if (memo[node][f] ! -1) {return memo[node][f];}int res0 (coins[node] >> f) - k;int res1 coins[no…

mybatis(57/134)

今天没什么想法&#xff0c;搭了个转账平台&#xff0c;加深了点之前javaweb的mvc架构的印象&#xff0c;还有异常的抛出处理等

ONNX 简介

ONNX &#xff08;Open Neural Network Exchange&#xff09;是一套表示深度神经网络模型的开放格式&#xff0c;由微软和 Facebook 于 2017 推出&#xff0c;然后迅速得到了各大厂商和框架的支持。目前&#xff0c;在数家机构的共同维护下&#xff0c;ONNX 已经对接了多种深度…

Linux的中断上半部和中断下半部的概念,并利用任务队列(Tasklet)实现中断下半部的处理

中断上半部和中断下半部的介绍 在Linux内核中&#xff0c;中断处理机制被设计成“中断上半部&#xff08;Top Half&#xff09;”和“中断下半部&#xff08;Bottom Half&#xff09;”两个部分&#xff0c;这种设计主要目的是提高系统的中断响应效率&#xff0c;同时减少中断…

数学规划问题2 .有代码(非线性规划模型,最大最小化模型,多目标规划模型)

非线性规划模型 FIrst:转化为标准型 在matlab中求非线性规划的函数 练习题: 典型例题: 最大最小化模型 核心思想&#xff1a; matlab的模型求解 经典例题: 多目标规划模型 基本概念 求解思路: 模型构建步骤 经典例题: 非线性规划模型 非线性规划&#xff08;Nonl…

linux 下tensorrt的yolov8的前向推理(c++ 版本)的实现

一、环境搭建 cuda 11.4 ubuntu 20.04 opencv-4.5.2 1.1 配置tensorrt 根据本机的硬件配置及cuda的版本&#xff0c;选择TensorRT-8.6.1.6的版本&#xff0c;下载网址为: TensorRT SDK | NVIDIA Developer 根据官网的说明&#xff0c;下载对应的压缩包即可。解压后&…

VUE elTree 无子级 隐藏展开图标

这4个并没有下级节点&#xff0c;即它并不是叶子节点&#xff0c;就不需求展示前面的三角展开图标! 查阅官方文档如下描述&#xff0c;支持bool和函数回调处理&#xff0c;这里咱们选择更灵活的函数回调实现。 给el-tree结构配置一下props&#xff0c;注意&#xff01; :pr…