【力扣周赛】第 360 场周赛(贪心 ⭐树上倍增)

news2024/11/29 5:40:00

文章目录

  • 竞赛链接
  • Q1:8015. 距离原点最远的点(贪心)
  • Q2:8022. 找出美丽数组的最小和(贪心)
  • Q3:2835. 使子序列的和等于目标的最少操作次数(贪心)
    • 思路
    • 竞赛时丑陋代码(有一说一没眼看,现在已经忘了当时是怎么想的了)
    • 优雅代码
  • Q4:2836. 在传球游戏中最大化函数值(⭐⭐⭐⭐⭐树上倍增)
    • 解法——利用倍增算法
    • 模板题——1483. 树节点的第 K 个祖先
  • 成绩记录

竞赛链接

https://leetcode.cn/contest/weekly-contest-360

Q1:8015. 距离原点最远的点(贪心)

https://leetcode.cn/problems/furthest-point-from-origin/

在这里插入图片描述

提示:
1 <= moves.length == n <= 50
moves 仅由字符 'L'、'R' 和 '_' 组成

抓住本质,R 和 L 是不能改变的,而 _ 是可以随意选择的,因此可以在最后决定 _ 往哪个方向走。

class Solution {
    public int furthestDistanceFromOrigin(String moves) {
        int ans = 0, cnt = 0, pos = 0;
        for (char ch: moves.toCharArray()) {
            if (ch == 'R') pos++;
            else if (ch == 'L') pos--;
            else cnt++;
        }
        return Math.abs(pos) + cnt;
    }
}

Q2:8022. 找出美丽数组的最小和(贪心)

https://leetcode.cn/problems/find-the-minimum-possible-sum-of-a-beautiful-array/

在这里插入图片描述

提示:
1 <= n <= 10^5
1 <= target <= 10^5

这道题目和 第 359 场周赛 中的 6450. k-avoiding 数组的最小总和 几乎一样。

我们还是用贪心来解决,从小到大,能选就选。

class Solution {
    public long minimumPossibleSum(int n, int target) {
        long ans = 0;
        Set<Integer> s = new HashSet<>();
        for (int i = 1; s.size() < n; ++i) {
            if (!s.contains(target - i)) {
                s.add(i);
                ans += i;
            }
        }
        return ans;
    }
}

Q3:2835. 使子序列的和等于目标的最少操作次数(贪心)

https://leetcode.cn/problems/minimum-operations-to-form-subsequence-with-target-sum/

在这里插入图片描述

提示:
1 <= nums.length <= 1000
1 <= nums[i] <= 2^30
nums 只包含非负整数,且均为 2 的幂。
1 <= target < 2^31

思路

首先确定 sum >= target 则一定有解,否则一定无解。
在这里插入图片描述

竞赛时丑陋代码(有一说一没眼看,现在已经忘了当时是怎么想的了)

class Solution {
    static Map<Integer, Integer> m = new HashMap(), m2 = new HashMap();
    static {
        for (int i = 0, v = 1; i <= 30; ++i, v *= 2) {
            m.put(v, i);
            m2.put(i, v);
        }
    }
    
    public int minOperations(List<Integer> nums, int target) {
        long sum = 0;
        int[] cnt = new int[31], cnt2 = new int[31];
        for (int num: nums) {
            sum += num;
            cnt[m.get(num)]++;
        }
        if (sum < target) return -1;
        
        for (int i = 30; i >= 0; --i) {
            if (target >= m2.get(i)) {
                cnt2[i]++;
                target -= m2.get(i);
            }
        }
        
        int v = 0, ans = 0, last = -1;
        for (int i = 0; i <= 30; ++i) {
            if (cnt[i] > cnt2[i]) {
                if (last != -1) {
                    ans += i - last;
                    last = -1;
                    v += (cnt[i] - cnt2[i] - 1) * m2.get(i);
                } else {
                    v += (cnt[i] - cnt2[i]) * m2.get(i);
                }
            } else if (cnt[i] < cnt2[i]) {
                if (v >= (cnt2[i] - cnt[i]) * m2.get(i)) {
                    v -= (cnt2[i] - cnt[i]) * m2.get(i);
                }
                else if (last == -1) last = i;
            }
        }
        return ans;
    }
}

优雅代码

https://leetcode.cn/problems/minimum-operations-to-form-subsequence-with-target-sum/solutions/2413344/tan-xin-by-endlesscheng-immn/

class Solution {
    public int minOperations(List<Integer> nums, int target) {
        long s = 0;                     // 求和
        long[] cnt = new long[31];      // 统计2^i的数量
        for (int x: nums) {
            s += x;
            cnt[Integer.numberOfTrailingZeros(x)]++;
        }
        if (s < target) return -1;      // 无解的情况
        int ans = 0, i = 0;
        s = 0;
        // 注意这里是1L,因为i 最大是 30,这是可以进循环的,但是加一后就变成 31 了,虽然一定不会进入循环,但是要在 while 那里判断一下。
        while ((1L << i) <= target) {
            s += cnt[i] << i;
            int mask = (int) ((1L << ++i) - 1);
            if (s >= (target & mask)) continue; // 检查当前和能否填补target部分
            ans++;                      // 否则需要分解更大的数字
            while (cnt[i] == 0) {
                ans++;
                i++;
            }
        }
        return ans;
    }
}

Q4:2836. 在传球游戏中最大化函数值(⭐⭐⭐⭐⭐树上倍增)

https://leetcode.cn/problems/maximize-value-of-function-in-a-ball-passing-game/

在这里插入图片描述

提示:
1 <= receiver.length == n <= 10^5
0 <= receiver[i] <= n - 1
1 <= k <= 10^10

解法——利用倍增算法

利用倍增算法,预处理每个节点 x 的第 2^i个祖先节点,以及从 x 的父节点到 x 的第 2^i 个祖先节点的节点编号之和。最后枚举起点 x,一边向上跳一边累加节点编号。

可以从代码模板中修改过来,多了要维护节点之间的和。

class Solution {
    public long getMaxFunctionValue(List<Integer> receiver, long k) {
        int n = receiver.size();        // 节点的个数
        int m = 64 - Long.numberOfLeadingZeros(k);      // k的二进制长度
        int[][] pa = new int[n][m];     // 节点x的第2^i个祖宗节点的变好
        long[][] sum = new long[n][m];  // 节点x的父节点到x的第2^i个祖宗节点的节点编号之和

        // 初始化dp数组
        for (int i = 0; i < n; ++i) {
            pa[i][0] = receiver.get(i);
            sum[i][0] = receiver.get(i);
        }

        // 递推dp数组(先枚举i,再枚举x)
        for (int i = 0; i < m - 1; ++i) {   // 注意这里的条件是 i < m - 1
            for (int x = 0; x < n; ++x) {
                int p = pa[x][i];
                pa[x][i + 1] = p < 0? -1: pa[p][i];
                // 合并节点的和 
                sum[x][i + 1] = sum[x][i] + sum[p][i];  
            }
        }

        long ans = 0;
        // 枚举各个节点作为起始节点
        for (int i = 0; i < n; ++i) {
            long s = i;
            int x = i;
            for (long t = k; t > 0; t &= t - 1) {
                int ctz = Long.numberOfTrailingZeros(t);
                // 要先处理求和,再处理节点的变化
                s += sum[x][ctz];   
                x = pa[x][ctz];
            }
            ans = Math.max(ans, s);
        }
        return ans;
    }
}

受 cpu 缓存的影响,倍增的二维数组开成 log*n 会比 n*log 快很多。
二维数组开成 logn * n 的形状会比开成 n * logn 的形状快很多,是因为在计算机中,连续的内存访问比随机的内存访问更快。当我们按行访问一个二维数组时,我们可以利用缓存行的概念,即将一行的数据读入缓存中,这样下一次访问时就可以直接从缓存中读取数据,而不需要再次从内存中读取。如果我们按列访问二维数组,则每次访问都需要跨越多个缓存行,这样会导致缓存失效,从而降低程序的性能。因此,将二维数组按行存储可以提高程序的性能

所以可以将代码修改成如下:

class Solution {
    public long getMaxFunctionValue(List<Integer> receiver, long k) {
        int n = receiver.size();        // 节点的个数
        int m = 64 - Long.numberOfLeadingZeros(k);      // k的二进制长度
        int[][] pa = new int[m][n];     // 节点x的第2^i个祖宗节点的变好
        long[][] sum = new long[m][n];  // 节点x的父节点到x的第2^i个祖宗节点的节点编号之和

        // 初始化dp数组
        for (int i = 0; i < n; ++i) {
            pa[0][i] = receiver.get(i);
            sum[0][i] = receiver.get(i);
        }

        // 递推dp数组(先枚举i,再枚举x)
        for (int i = 0; i < m - 1; ++i) {   // 注意这里的条件是 i < m - 1
            for (int x = 0; x < n; ++x) {
                int p = pa[i][x];
                pa[i + 1][x] = p < 0? -1: pa[i][p];
                // 合并节点的和 
                sum[i + 1][x] = sum[i][x] + sum[i][p];  
            }
        }

        long ans = 0;
        // 枚举各个节点作为起始节点
        for (int i = 0; i < n; ++i) {
            long s = i;
            int x = i;
            for (long t = k; t > 0; t &= t - 1) {
                int ctz = Long.numberOfTrailingZeros(t);
                // 要先处理求和,再处理节点的变化
                s += sum[ctz][x];   
                x = pa[ctz][x];
            }
            ans = Math.max(ans, s);
        }
        return ans;
    }
}

执行用时从 237ms 加速到了 65ms 。

模板题——1483. 树节点的第 K 个祖先

https://leetcode.cn/problems/kth-ancestor-of-a-tree-node/description/

在这里插入图片描述

提示:
1 <= k <= n <= 5 * 10^4
parent[0] == -1 表示编号为 0 的节点是根节点。
对于所有的 0 < i < n ,0 <= parent[i] < n 总成立
0 <= node < n
至多查询 5 * 10^4 次

https://leetcode.cn/problems/kth-ancestor-of-a-tree-node/solutions/2305895/mo-ban-jiang-jie-shu-shang-bei-zeng-suan-v3rw/
在这里插入图片描述

本质上是动态规划,记 pa[x][i] 为每个节点 x 的第 2^i 个祖先节点。(如果不存在则为 -1)。

计算方式如下:
在这里插入图片描述
pa[x][1] = pa[pa[x][0]][0] 的意思是,x 节点的爷爷是 x 节点的父亲的父亲。
一般的,有 pa[x][i + 1] = pa[pa[x][i]][i]。

class TreeAncestor {
    int[][] pa;

    // 使用原始数据将整个 pa 数组预处理出来
    public TreeAncestor(int n, int[] parent) {
        int m = 32 - Integer.numberOfLeadingZeros(n);   // n的二进制长度
        pa = new int[n][m];                 // 表示节点i的2^j个祖宗节点
        // 初始化dp数组,即填充每个节点的父亲节点
        for (int i = 0; i < n; ++i) {
            pa[i][0] = parent[i];
        }
        // 先枚举i,再枚举x
        // 相当于先算出所有爷爷节点,再算出所有爷爷的爷爷节点
        for (int i = 0; i < m - 1; i++) {
            for (int x = 0; x < n; ++x) {
                int p = pa[x][i];   // 取出x的第2^i个祖宗节点
                // x的第2^(i+1)个祖宗节点 等于 x的第2^i个祖宗节点的第2^i个祖宗节点
                pa[x][i + 1] = p < 0? -1: pa[p][i]; 
            }
        }
    }
    
    // 取出node节点的第k个祖宗节点
    public int getKthAncestor(int node, int k) {
        // 写法1 从低位到高位枚举
        // int m = 32 - Integer.numberOfLeadingZeros(k);   // k的二进制长度
        // for (int i = 0; i < m; ++i) {
        //     if ((k >> i & 1) == 1) {        // k的二进制当前位为1
        //         node = pa[node][i];
        //         if (node < 0) break;
        //     }
        // }
        // return node;

        // 写法2 不断去掉k末尾的1
        for (; k != 0 && node != -1; k &= k - 1) {
            node = pa[node][Integer.numberOfTrailingZeros(k)];
        }
        return node;
    }   
}

/**
 * Your TreeAncestor object will be instantiated and called as such:
 * TreeAncestor obj = new TreeAncestor(n, parent);
 * int param_1 = obj.getKthAncestor(node,k);
 */

成绩记录

在这里插入图片描述

最后一题实在是写不出来了。(不过还好好像大家也都写不出来)
在这里插入图片描述

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

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

相关文章

SquirrelMail实现Web方式收发邮件_xionglling的博客-CSDN博客

SquirrelMail实现Web方式收发邮件_xionglling的博客-CSDN博客小松鼠实现Web邮件服务SquirrelMail 是一个用PHP开发的Web邮件系统。它内置纯PHP支持的IMAP和SMTP协议&#xff0c;所有页面都遵循 HTML 4.0标准(没有使用任何 JavaScript 代码)&#xff0c;以便最大限度兼容各种多浏…

java对象的组成部分

在 HotSpot 虚拟机里&#xff0c;对象在堆内存中的存储布局可以划分为三个部分&#xff1a;对象头&#xff08;Header&#xff09;、实例数据&#xff08;Instance Data&#xff09;和对齐填充&#xff08;Padding&#xff09; 对象头主要由两部分组成&#xff1a; 第一部分存…

详细介绍 display: block(块级元素)、inline-block(行内块元素)和inline(行内元素)的差别

html元素的类型主要可分为块级元素、行内元素、行内块元素分别对应的各自的display属性&#xff0c;block、inline、inline-block html的标签都被默认设置了对应的display属性值&#xff0c;例如 块级元素&#xff1a;默认设置display:block的元素 <div>、<h1>~…

无涯教程-JavaScript - NETWORKDAYS函数

描述 NETWORKDAYS函数返回start_date和end_date之间的整个工作日数。工作日不包括周末和节假日中确定的任何日期。 语法 NETWORKDAYS (start_date, end_date, [holidays])争论 Argument描述Required/OptionalStart_dateA date that represents the start date.RequiredEnd_…

软件游戏丢失d3dcompiler_47.dll怎么办?这个几个解决方法可修复

当我们在玩软件游戏时&#xff0c;有时候会出现丢失 d3dcompiler_47.dll 的问题&#xff0c;这让我们感到非常困扰。d3dcompiler_47.dll 是 DirectX 中的一个重要组件&#xff0c;如果它丢失了&#xff0c;那么很多游戏就无法正常运行。我将和大家分享一下我在解决软件游戏丢失…

美妆+七人拼团模式:如何打造新型社交电商营销方式

美妆是一个充满竞争和创新的行业&#xff0c;要想在市场上获得优势&#xff0c;就需要不断寻找新的营销方式&#xff0c;吸引和留住消费者。七人拼团模式就是一种结合了社交电商和拼购玩法的新型商业模式&#xff0c;它可以利用社交网络的裂变效应&#xff0c;增加品牌曝光度和…

我国元宇宙相关专利数居世界第二,中创元宇宙发展取得阶段性进步!

元宇宙是工业和互联网的下一次大变革方向&#xff0c;将划分出一个时代 9月2日&#xff0c;2023年中国国际服务贸易交易会&#xff08;以下简称“服贸会”&#xff09; 在京召开。 在同期举行的数字贸易发展趋势和前沿高峰论坛上&#xff0c;我国元宇宙产业生态在各方的支持下…

2.IDE的优化与插件

文章目录 后端IDEA配置maven配置git配置名字插件安装参考资料 前端vs codeopenssh远程环境开发 后端IDEA 配置maven 参考&#xff1a;https://blog.csdn.net/weixin_44458365/article/details/118416385 -DarchetypeCataloginternal注意&#xff1a;一旦勾选下面的选项&…

SIP mini对讲 SV-10/SV-10W 86型sip对讲终端

SIP mini对讲 SV-10/SV-10W 86型sip对讲终端 A10系列是专门针对室内用户需求研发的一款SIP mini 对讲产品&#xff0c;集智能安防、音频对讲和广播功能于一体&#xff0c;功能强大&#xff0c;性价比高。它外观小巧&#xff0c;支持按键图标/功能自定义&#xff0c;配备3个可编…

Git常用命令用法

参考视频&#xff1a;真的是全能保姆 git、github 保姆级教程入门&#xff0c;工作和协作必备技术&#xff0c;github提交pr - pull request_哔哩哔哩_bilibili 1.Git初始化 首先设置名称和邮箱。然后初始化一下&#xff0c;然后就创建了一个空的Git仓库。 PS D:\golang\oth…

手机word怎么转pdf?这几种方法很简单

手机word怎么转pdf&#xff1f;将word文档转换为PDF文件&#xff0c;在很多场合都非常有用。比如&#xff0c;你可能需要在公司或学校中分享一份重要的文档&#xff0c;或者你想将一份简历或报告以PDF格式发送给招聘人员或老师。无论是哪种情况&#xff0c;将word文档转换为PDF…

Nginx一主一从配置Keepalive

文章目录 机器规划监控Nginx进程安装配置Keepalive验证高可用性 机器规划 主机vip内网ipNginx1192.168.xxx.xx192.168.xxx.abNginx2192.168.xxx.xx192.168.xxx.cd 监控Nginx进程 Nginx监控脚本&#xff0c;监控nginx&#xff0c;如果nginx停了&#xff0c;那么杀掉keepalive…

性能强悍价格到位,老牌NAS也玩性价比

前几天看到站内爆料铁威马的优惠信息&#xff0c;搭载 N5095 的 F4-423 到手不到 1900&#xff0c;一看之下着实有些心动&#xff0c;说起来我折腾了这么多 NAS&#xff0c;铁威马还真没试过。稍作思考直接下单&#xff0c;毕竟能够存在这么多年的 NAS 品牌&#xff0c;没点自己…

Java I/O模型发展以及Netty网络模型的设计思想

Java I/O模型发展以及Netty网络模型的设计思想 I/O模型Java BIOJava NIOJava AIO NIO Reactor网络模型单Reactor单线程模型单Reactor多线程模型主从Reactor多线程模型 Netty通信框架 前言&#xff1a; BIO、NIO的代码实践参考&#xff1a;Java分别用BIO、NIO实现简单的客户端服…

Redis Redis介绍、安装 - Redis客户端

目录 redis是什么&#xff0c;他的应用场景是什么&#xff1f; Redis的一些主要特点和应用场景&#xff1a; redis的官方网站&#xff1a;Redis redis是键值型数据库&#xff1a;&#xff08;也就是key-value模式&#xff09;&#xff08;跟python的字典很像&#xff09; …

渗透测试漏洞原理之---【SSRF 服务端请求伪造】

文章目录 1、SSRF概述1.1、场景1.1.1、PHP代码实现 1.2、SSRF原理1.3、SSRF危害 2、SSRF攻防2.1、SSRF利用2.1.1、文件访问2.1.2、端口扫描2.1.3、读取本地文件2.1.4、内网应用指纹识别2.1.5、攻击内网Web应用 2.2、SSRF示例2.3、SSRF防御2.3.1、过滤输入2.3.2、过滤输出 3、SS…

【知网检索稳定】第三届社会发展与媒体传播国际学术会议(SDMC 2023)

第三届社会发展与媒体传播国际学术会议&#xff08;SDMC 2023&#xff09; 2023 3rd International Conference on Social Development and Media Communication 第三届社会发展与媒体传播国际学术会议 (SDMC 2023)将于2023年11月03-05日在中国杭州召开。会议主题主要围绕社会…

【紫光同创国产FPGA教程】——【PGL22G第七章】串口收发实验例程

本原创教程由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处 适用于板卡型号&#xff1a; 紫光同创PGL22G开发平台&#xff08;盘古22K&#xff09; 一&#xff1a;盘古22K开发板&#xff08;紫光同创PGL22G开…

PACS三维医学影像处理系统源码

三维医学图像处理系统&#xff08;PACS&#xff09;源码 系统概述&#xff1a; 影像归档和通信系统PACS集影像存储服务器、影像诊断工作站及RIS报告系统于一身,主要有图像处理模块、影像数据管理模块、RIS报告模块、光盘存档模块、DICOM通讯模块、胶片打印输出等模块组成&…

攻防世界-easychallenge

原题 解题思路 下载下来是一个pyc文件&#xff0c;还是反编译python工具 final就是flag&#xff0c;先经过异或&#xff0c;又经过base32加密。倒过来操作就行。