周赛357(模拟、脑经急转弯、多源BFS+并查集、反悔贪心)

news2024/12/23 23:35:17

文章目录

  • 周赛357
    • [2810. 故障键盘](https://leetcode.cn/problems/faulty-keyboard/)
      • 模拟
      • 双端队列O(n)
    • [2811. 判断是否能拆分数组](https://leetcode.cn/problems/check-if-it-is-possible-to-split-array/)
      • 脑经急转弯
    • [2812. 找出最安全路径](https://leetcode.cn/problems/find-the-safest-path-in-a-grid/)
      • 多源BFS + 倒序枚举 + 并查集
    • [2813. 子序列最大优雅度](https://leetcode.cn/problems/maximum-elegance-of-a-k-length-subsequence/)
      • 反悔贪心

周赛357

2810. 故障键盘

难度简单0

你的笔记本键盘存在故障,每当你在上面输入字符 'i' 时,它会反转你所写的字符串。而输入其他字符则可以正常工作。

给你一个下标从 0 开始的字符串 s ,请你用故障键盘依次输入每个字符。

返回最终笔记本屏幕上输出的字符串。

示例 1:

输入:s = "string"
输出:"rtsng"
解释:
输入第 1 个字符后,屏幕上的文本是:"s" 。
输入第 2 个字符后,屏幕上的文本是:"st" 。
输入第 3 个字符后,屏幕上的文本是:"str" 。
因为第 4 个字符是 'i' ,屏幕上的文本被反转,变成 "rts" 。
输入第 5 个字符后,屏幕上的文本是:"rtsn" 。
输入第 6 个字符后,屏幕上的文本是: "rtsng" 。
因此,返回 "rtsng" 。

示例 2:

输入:s = "poiinter"
输出:"ponter"
解释:
输入第 1 个字符后,屏幕上的文本是:"p" 。
输入第 2 个字符后,屏幕上的文本是:"po" 。
因为第 3 个字符是 'i' ,屏幕上的文本被反转,变成 "op" 。
因为第 4 个字符是 'i' ,屏幕上的文本被反转,变成 "po" 。
输入第 5 个字符后,屏幕上的文本是:"pon" 。
输入第 6 个字符后,屏幕上的文本是:"pont" 。
输入第 7 个字符后,屏幕上的文本是:"ponte" 。
输入第 8 个字符后,屏幕上的文本是:"ponter" 。
因此,返回 "ponter" 。

提示:

  • 1 <= s.length <= 100
  • s 由小写英文字母组成
  • s[0] != 'i'

模拟

class Solution {
    public String finalString(String s) {
        StringBuilder sb = new StringBuilder();
        for(char c : s.toCharArray()){
            if(c != 'i') sb.append(c);
            else{
                sb.reverse();
            }
        }
        return sb.toString();
    }
}

双端队列O(n)

把反转看成是后续往字符串的头部添加字符。

这可以用双端队列实现。

class Solution {
    public String finalString(String s) {
        Deque<Character> dq = new ArrayDeque<>();
        boolean tail = true; // 填入尾部还是头部
        for(char c : s.toCharArray()){
            if(c == 'i') tail = !tail;
            else if(tail) dq.addLast(c);
            else dq.addFirst(c);
        }
        StringBuilder sb = new StringBuilder();
        for(char c : dq) sb.append(c);
        if(!tail) sb.reverse();
        return sb.toString();
    }
}

2811. 判断是否能拆分数组

难度中等3

给你一个长度为 n 的数组 nums 和一个整数 m 。请你判断能否执行一系列操作,将数组拆分成 n非空 数组。

在每一步操作中,你可以选择一个 长度至少为 2 的现有数组(之前步骤的结果) 并将其拆分成 2 个子数组,而得到的 每个 子数组,至少 需要满足以下条件之一:

  • 子数组的长度为 1 ,或者
  • 子数组元素之和 大于或等于 m

如果你可以将给定数组拆分成 n 个满足要求的数组,返回 true ;否则,返回 false

**注意:**子数组是数组中的一个连续非空元素序列。

示例 1:

输入:nums = [2, 2, 1], m = 4
输出:true
解释:
第 1 步,将数组 nums 拆分成 [2, 2] 和 [1] 。
第 2 步,将数组 [2, 2] 拆分成 [2] 和 [2] 。
因此,答案为 true 。

示例 2:

输入:nums = [2, 1, 3], m = 5 
输出:false
解释:
存在两种不同的拆分方法:
第 1 种,将数组 nums 拆分成 [2, 1] 和 [3] 。
第 2 种,将数组 nums 拆分成 [2] 和 [1, 3] 。
然而,这两种方法都不满足题意。因此,答案为 false 。

示例 3:

输入:nums = [2, 3, 3, 2, 3], m = 6
输出:true
解释:
第 1 步,将数组 nums 拆分成 [2, 3, 3, 2] 和 [3] 。
第 2 步,将数组 [2, 3, 3, 2] 拆分成 [2, 3, 3] 和 [2] 。
第 3 步,将数组 [2, 3, 3] 拆分成 [2] 和 [3, 3] 。
第 4 步,将数组 [3, 3] 拆分成 [3] 和 [3] 。
因此,答案为 true 。 

提示:

  • 1 <= n == nums.length <= 100
  • 1 <= nums[i] <= 100
  • 1 <= m <= 200

脑经急转弯

看样例3

class Solution {
    public boolean canSplitArray(List<Integer> nums, int m) {
        if(nums.size() <= 2) return true;
        for(int i = 1; i < nums.size(); i++){
            if(nums.get(i) + nums.get(i-1) >= m) return true;
        }
        return false;
    }
}

2812. 找出最安全路径

难度中等10

给你一个下标从 0 开始、大小为 n x n 的二维矩阵 grid ,其中 (r, c) 表示:

  • 如果 grid[r][c] = 1 ,则表示一个存在小偷的单元格
  • 如果 grid[r][c] = 0 ,则表示一个空单元格

你最开始位于单元格 (0, 0) 。在一步移动中,你可以移动到矩阵中的任一相邻单元格,包括存在小偷的单元格。

矩阵中路径的 安全系数 定义为:从路径中任一单元格到矩阵中任一小偷所在单元格的 最小 曼哈顿距离。

返回所有通向单元格 (n - 1, n - 1) 的路径中的 最大安全系数

单元格 (r, c) 的某个 相邻 单元格,是指在矩阵中存在的 (r, c + 1)(r, c - 1)(r + 1, c)(r - 1, c) 之一。

两个单元格 (a, b)(x, y) 之间的 曼哈顿距离 等于 | a - x | + | b - y | ,其中 |val| 表示 val 的绝对值。

示例 1:

img

输入:grid = [[1,0,0],[0,0,0],[0,0,1]]
输出:0
解释:从 (0, 0) 到 (n - 1, n - 1) 的每条路径都经过存在小偷的单元格 (0, 0) 和 (n - 1, n - 1) 。

示例 2:

img

输入:grid = [[0,0,1],[0,0,0],[0,0,0]]
输出:2
解释:
上图所示路径的安全系数为 2:
- 该路径上距离小偷所在单元格(0,2)最近的单元格是(0,0)。它们之间的曼哈顿距离为 | 0 - 0 | + | 0 - 2 | = 2 。
可以证明,不存在安全系数更高的其他路径。

示例 3:

img

输入:grid = [[0,0,0,1],[0,0,0,0],[0,0,0,0],[1,0,0,0]]
输出:2
解释:
上图所示路径的安全系数为 2:
- 该路径上距离小偷所在单元格(0,3)最近的单元格是(1,2)。它们之间的曼哈顿距离为 | 0 - 1 | + | 3 - 2 | = 2 。
- 该路径上距离小偷所在单元格(3,0)最近的单元格是(3,2)。它们之间的曼哈顿距离为 | 3 - 3 | + | 0 - 2 | = 2 。
可以证明,不存在安全系数更高的其他路径。

提示:

  • 1 <= grid.length == n <= 400
  • grid[i].length == n
  • grid[i][j]01
  • grid 至少存在一个小偷

多源BFS + 倒序枚举 + 并查集

第三题主站出过好几次了,1631,1970,2258都是这个套路,这次这个和这些里前两个比较像,那就是二分猜答案,dijkstra,并查集三种做法(二分猜答案的确是有点卡常). 还有778和2577

class Solution {
    private final static int[][] dirts = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    public int maximumSafenessFactor(List<List<Integer>> grid) {
        int n = grid.size();
        // 1. 从所有1出发,写一个多源BFS,计算出每个格子(i, j)到最近的 1 的曼哈顿距离dis[i][j]
        List<int[]> q = new ArrayList<>();
        int[][] dis = new int[n][n];
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                if(grid.get(i).get(j) > 0)
                    q.add(new int[]{i, j});
                else dis[i][j] = -1;
            }   
        }
        // 将坐标按每个距离从小到大进行分组,后面倒序枚举答案时需要合并对应分组
        List<List<int[]>> groups = new ArrayList<>();
        groups.add(q);
        while(!q.isEmpty()){ // 多源BFS
            List<int[]> tmp = q;
            q = new ArrayList<>();
            for(int[] p : tmp){
                for(int[] d : dirts){
                    int x = p[0] + d[0], y = p[1] + d[1];
                    if(0 <= x && x < n && 0 <= y && y < n && dis[x][y] < 0){
                        q.add(new int[]{x, y});
                        dis[x][y] = groups.size();
                    }
                }
            }
            groups.add(q); // 相同 dis 分组记录
        }

        // 并查集
        fa = new int[n * n];
        for(int i = 0; i < n * n; i++)
            fa[i] = i;
        // 由于多源BFS时最后会添加上一个空的list,因此答案从倒数第二个开始枚举
        for(int ans = groups.size() - 2; ans > 0; ans--){
            // 1. 合并分组  2. 判断
            List<int[]> g = groups.get(ans);
            for(int[] p : g){ // 枚举分组中的点,将其与四个方向上距离远的点合并
                int i = p[0], j = p[1];
                for(int[] d : dirts){
                    int x = i + d[0], y = j + d[1];
                    // dis[x][y] >= dis[i][j] 说明 相邻的点已经加入并查集中
                    if(0 <= x && x < n && 0 <= y && y < n && dis[x][y] >= dis[i][j]){
                        fa[find(x * n + y)] = find(i * n + j);
                        // fa[find(i * n + j)] = find(x * n + y); 也可以
                    }
                }
            }
            if(find(0) == find(n * n - 1)) return ans;
        }
        return 0;
    }

    // 并查集模板
    private int[] fa;

    private int find(int x) {
        if (fa[x] != x) fa[x] = find(fa[x]);
        return fa[x];
    }
}

2813. 子序列最大优雅度

难度困难6

给你一个长度为 n 的二维整数数组 items 和一个整数 k

items[i] = [profiti, categoryi],其中 profiticategoryi 分别表示第 i 个项目的利润和类别。

现定义 items子序列优雅度 可以用 total_profit + distinct_categories2 计算,其中 total_profit 是子序列中所有项目的利润总和,distinct_categories 是所选子序列所含的所有类别中不同类别的数量。

你的任务是从 items 所有长度为 k 的子序列中,找出 最大优雅度

用整数形式表示并返回 items 中所有长度恰好为 k 的子序列的最大优雅度。

**注意:**数组的子序列是经由原数组删除一些元素(可能不删除)而产生的新数组,且删除不改变其余元素相对顺序。

示例 1:

输入:items = [[3,2],[5,1],[10,1]], k = 2
输出:17
解释:
在这个例子中,我们需要选出长度为 2 的子序列。
其中一种方案是 items[0] = [3,2] 和 items[2] = [10,1] 。
子序列的总利润为 3 + 10 = 13 ,子序列包含 2 种不同类别 [2,1] 。
因此,优雅度为 13 + 22 = 17 ,可以证明 17 是可以获得的最大优雅度。 

示例 2:

输入:items = [[3,1],[3,1],[2,2],[5,3]], k = 3
输出:19
解释:
在这个例子中,我们需要选出长度为 3 的子序列。 
其中一种方案是 items[0] = [3,1] ,items[2] = [2,2] 和 items[3] = [5,3] 。
子序列的总利润为 3 + 2 + 5 = 10 ,子序列包含 3 种不同类别 [1, 2, 3] 。 
因此,优雅度为 10 + 32 = 19 ,可以证明 19 是可以获得的最大优雅度。

示例 3:

输入:items = [[1,1],[2,1],[3,1]], k = 3
输出:7
解释:
在这个例子中,我们需要选出长度为 3 的子序列。
我们需要选中所有项目。
子序列的总利润为 1 + 2 + 3 = 6,子序列包含 1 种不同类别 [1] 。
因此,最大优雅度为 6 + 12 = 7 。

提示:

  • 1 <= items.length == n <= 105
  • items[i].length == 2
  • items[i][0] == profiti
  • items[i][1] == categoryi
  • 1 <= profiti <= 109
  • 1 <= categoryi <= n
  • 1 <= k <= n

反悔贪心

题解:https://leetcode.cn/problems/maximum-elegance-of-a-k-length-subsequence/solution/fan-hui-tan-xin-pythonjavacgo-by-endless-v2w1/

先按profit从大到小排序,再获取profit最大的前k项,

后续的项(n-k)如果要提升整体值,唯有通过增加category数目来优化。

class Solution {
    /*
    找到一个 base, 先选最大的 k 个利润,这可能是一个答案
    
    考虑下一个项目要不要选
    由于利润从大到小排序,利润和 total profit 不会变大
    所以重点就在 distinct_categories 能不能变大? (考虑变化量)

    分类讨论:
    1. 如果新添加的项目的类别之前选过了,那么 distinct_categories 不会变大
    2. 如果新添加的项目的类别之前没选过(没出现过)
    2.1 如果移除的项目的类别只有一个,那么 distinct_categories-1+1,不变,不行
    2.2 如果移除的项目的类别有多个,那么 distinct_categories+1,这种情况就是可以的
        - 选一个利润最小的移除,用一个栈维护
    */
    public long findMaximumElegance(int[][] items, int k) {
        Arrays.sort(items, (a, b) -> b[0] - a[0]); // 按利润从大到小排序
        long ans = 0, totalProfit = 0;
        Set<Integer> vis = new HashSet<>();
        Deque<Integer> duplicate = new ArrayDeque<>(); // 重复类别的利润
        for(int i = 0; i < items.length; i++){
            int profit = items[i][0], category = items[i][1];
            if(i < k){
                totalProfit += profit;
                if(!vis.add(category)) // 重复类别
                    duplicate.push(profit);
            }else if(!duplicate.isEmpty() && vis.add(category)){
                totalProfit += profit - duplicate.pop(); // 选一个重复类别中的最小利润替换
            }// else:比前面的利润小,而且类别还重复了,
            //      选它只会让 totalProfit 变小,vis.size() 不变,优雅度不会变大
            ans = Math.max(ans, totalProfit + (long)vis.size() * vis.size());
        }
        return ans;
    }
}

871.最低加油次数

LCP 30. 魔塔游戏

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

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

相关文章

SpringBoot系列---【三种启动传参方式的区别】

三种启动传参方式的区别 1.三种方式分别是什么? idea中经常看到下面三种启动传参方式 优先级 Program arguments > VM options > Environment variable > 系统默认值 2.参数说明 2.1、VM options VM options其实就是我们在程序中需要的运行时环境变量&#xff0c;它需…

实现Jenkins自动发包配置

参考抖音&#xff1a;Java不良人 其中的视频演示代码 不推荐把jenkins端口一直开放&#xff0c;推荐使用时候放开&#xff08;版本不太新&#xff0c;避免漏洞攻击&#xff09; [rootVM-4-12-centos soft]# docker-compose -v Docker Compose version v2.19.1docker-compose.…

TCP三次握手四次断开

一、了解TCP &#x1f345;TCP &#xff1a;传输控制协议&#xff0c;是一种面向连接的可靠的传输协议。 什么是可靠的传输协议&#xff1f;如何保障可靠传输&#xff1f; 保证可靠性&#xff1a; 1.确认机制 2.重传输机制什么是面向连接&#xff1f;如何保障面…

C语言 | 位运算符>>的高级用法

一、人物简介 第一位闪亮登场&#xff0c;有请今后会一直教我们C语言的老师 —— 自在。 第二位上场的是和我们一起学习的小白程序猿 —— 逍遥。 二、优化除法运算 除法运算需要比位移运算需要更多的计算资源&#xff0c;某些情况下采用位移运算可以提高性能 代码示例 #in…

代码随想录算法训练营第51天|动态规划part09|198.打家劫舍、213.打家劫舍II、337.打家劫舍III

代码随想录算法训练营第51天&#xff5c;动态规划part09&#xff5c;198.打家劫舍、213.打家劫舍II、337.打家劫舍III 198.打家劫舍 198.打家劫舍 思路&#xff1a; 仔细一想&#xff0c;当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。 所以这里就更感觉到&a…

VectorDBBench向量数据库性能评测工具

目录 一、背景和意义 二、特点和优势 三、应用场景和实际效果 四、总结 摘要: VectorDBBench.com是一个基于云计算的向量数据库基准测试平台,旨在评估不同向量数据库的性能和可扩展性。本文介绍了VectorDBBench的背景和意义,分析了VectorDBBench的特点和优势,并从多个方…

C# Atrribute和反射的简单例子

Attribute 需要以Attribute 结尾, 并继承Attribute namespace AttributeTest {public class HeroAttribute : Attribute{} }namespace AttributeTest {public class SkillAttribute : Attribute{} }namespace AttributeTest {[Hero]public class Blademaster{[Skill]public vo…

【PCB专题】Allegro中如何自动查找并删除不使用的规则

在Allegro软件使用中,我们经常是从上一个版本修改而来的。那么就会遇到有些多余规则没有使用的情况,怎么能够知道哪些规则没有使用并删除呢? 如下所示在Electrical中的All Constraints下存在SDIO规则和WIFI_SDIO规则。这两个规则是重复的,只是名称不同而已。 在规则的使…

前端工具类

日期类 1️⃣ 新建index.js文件/*** param {date} time 需要转换的时间* param {String} fmt 需要转换的格式 如 yyyy-MM-dd、yyyy-MM-dd HH:mm:ss*/ export function formatTime(time, fmt) {if (!time) {return "";}else {const date new Date(time);const o {M:…

[深度学习入门]PyTorch深度学习[数组变形、批量处理、通用函数、广播机制]

目录 一、前言二、数组变形2.1 更改数组的形状2.1.1 reshape2.1.2 resize2.1.3 T(转置)2.1.4 ravel2.1.5 flatten2.1.6 squeeze2.1.7 transpose 2.2 合并数组2.2.1 append2.1.2 concatenate2.1.3 stack 三、批量处理四、通用函数4.1 math 与 numpy 函数的性能比较4.2 循环与向量…

无涯教程-Perl - endhostent函数

描述 此函数告诉系统您不再希望使用gethostent从hosts文件读取条目。 语法 以下是此函数的简单语法- endhostent返回值 此函数不返回任何值。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perlwhile( ($name, $aliases, $addrtype, $length, addrs)gethostent() ) …

Android 网络协议与网络编程

一、TCP/IP协议 Transmission Control Protocol/Internet Protocol的简写&#xff0c;中译名为传输控制协议/因特网互联 协议&#xff0c;是Internet最基本的协议、Internet国际互联网络的基础&#xff0c;由网络层的IP协议和传输层的TCP 协议组成。协议采用了4层的层级结构。…

ad+硬件每日学习十个知识点(24)23.8.4(时序约束,SignalTap Ⅱ)

文章目录 1.建立时间和保持时间2.为什么要建立时序约束&#xff1f;3.SignalTap Ⅱ4.SignalTap Ⅱ使用方法5.HDL的仿真软件&#xff08;modelsim&#xff09;6.阻抗匹配 1.建立时间和保持时间 答&#xff1a; 2.为什么要建立时序约束&#xff1f; 答&#xff1a; 3.Sign…

基于STM32CUBEMX驱动低压步进器电机驱动器STSPIN220(3)----定时器中断产生指定数量脉冲

基于STM32CUBEMX驱动低压步进器电机驱动器STSPIN220----3.定时器中断产生指定数量脉冲 概述样品申请视频教学STM32CUBEMX配置产生固定数量的PWM电机设置STSPIN220初始化主程序 概述 在步进电机控制过程中&#xff0c;为了实现精确的位置和速度控制&#xff0c;经常需要输出指定…

tomcat配置文件和web站点部署(zrlog)简介

一.tomcat/apache-tomcat-8.5.70/conf/server.xml组件类别介绍 1.类别 2.Connector参数 3.host参数 4.Context参数 二.web站点部署(以zrlog为例) 1.将zrlog的war包传到webapps下面 2.在mysql数据库中创建zrlog用户并赋予权限 3.完成安装向导&#xff0c;登录管理界面即可…

分布式链路追踪概述

分布式链路追踪概述 文章目录 分布式链路追踪概述1.分布式链路追踪概述1.1.什么是 Tracing1.2.为什么需要Distributed Tracing 2.Google Dapper2.1.Dapper的分布式跟踪2.1.1.跟踪树和span2.1.2.Annotation2.1.3.采样率 3.OpenTracing3.1.发展历史3.2.数据模型 4.java探针技术-j…

【福建事业单位-推理判断】08逻辑论证-加强-原因解释-日常总结

福建事业单位-推理判断】08逻辑论证-加强 一、加强题1.1 建立联系——搭桥1.2 补充论据必要条件&#xff08;没它不行&#xff09;补充论据&#xff08;解释原因和举例论证&#xff09; 总结 二、原因解释题三、日常结论复习建议 一、加强题 加强的题型&#xff0c;一般只加强…

【HMS Core】推送报错907135701、分析数据查看

【关键字】 HMS、推送服务、分析服务 【问题描述1】 集成推送服务&#xff0c;获取Token时报错 907135701: scope list empty 【解决方案】 907135701OpenGW没有配置Scope 1、您可以检查下网络是否有问题&#xff0c;手机是否可以正常连接互联网 2、查看推送服务开关是否正…

高压放大器芯片的作用和用途是什么呢

高压放大器芯片是一种应用于电子、通信、医疗等领域的电子元件&#xff0c;它可以将输入信号放大到足以驱动负载所需的电平&#xff0c;并具有高性能、高可靠性和高效率等特点。下面安泰电子将详细介绍高压放大器芯片的作用和用途&#xff1a; 图&#xff1a;ATA-7000系列高压放…

04-5_Qt 5.9 C++开发指南_QComboBox和QPlainTextEdit

文章目录 1. 实例功能概述2. 源码2.1 可视化UI设计2.2 widget.h2.3 widget.cpp 1. 实例功能概述 QComboBox 是下拉列表框组件类&#xff0c;它提供一个下拉列表供用户选择&#xff0c;也可以直接当作一个QLineEdit 用作输入。OComboBox 除了显示可见下拉列表外&#xff0c;每个…