周赛346(括号匹配问题变形、双指针、模拟/打表预处理+DFS)

news2025/1/17 9:01:58

文章目录

  • 周赛346
    • [2696. 删除子串后的字符串最小长度](https://leetcode.cn/problems/minimum-string-length-after-removing-substrings/)
      • 暴力模拟
      • 使用栈
    • [2697. 字典序最小回文串](https://leetcode.cn/problems/lexicographically-smallest-palindrome/)
      • 双指针
    • [2698. 求一个整数的惩罚数](https://leetcode.cn/problems/find-the-punishment-number-of-an-integer/)
      • 模拟(枚举 + DFS)
      • 预处理(打表) + DFS
    • [2699. 修改图中的边权](https://leetcode.cn/problems/modify-graph-edge-weights/)
      • 两次Dijkstra

周赛346

2696. 删除子串后的字符串最小长度

难度简单2

给你一个仅由 大写 英文字符组成的字符串 s

你可以对此字符串执行一些操作,在每一步操作中,你可以从 s 中删除 任一个 "AB""CD" 子字符串。

通过执行操作,删除所有 "AB""CD" 子串,返回可获得的最终字符串的 最小 可能长度。

注意,删除子串后,重新连接出的字符串可能会产生新的 "AB""CD" 子串。

示例 1:

输入:s = "ABFCACDB"
输出:2
解释:你可以执行下述操作:
- 从 "ABFCACDB" 中删除子串 "AB",得到 s = "FCACDB" 。
- 从 "FCACDB" 中删除子串 "CD",得到 s = "FCAB" 。
- 从 "FCAB" 中删除子串 "AB",得到 s = "FC" 。
最终字符串的长度为 2 。
可以证明 2 是可获得的最小长度。

示例 2:

输入:s = "ACBBD"
输出:5
解释:无法执行操作,字符串长度不变。

提示:

  • 1 <= s.length <= 100
  • s 仅由大写英文字母组成

暴力模拟

class Solution {
    public int minLength(String s) {
        int i = 1;
        while(i < s.length()){
            if(s.charAt(i) == 'B' && s.charAt(i-1) == 'A'){
                s = s.substring(0,i-1) + s.substring(i+1);
                i = 0;
            } else if(s.charAt(i) == 'D' && s.charAt(i-1) == 'C'){
                s = s.substring(0,i-1) + s.substring(i+1);
                i = 0;
            }
            i++;
        }
        return s.length();
    }
}

java暴力替换:api

class Solution {
    public int minLength(String s) {
        while(s.contains("AB") || s.contains("CD"))
            s =s.replace("AB", "").replace("CD", "");
        return s.length();
    }
}

时间复杂度:O(n^2)

使用栈

用栈记录遍历过的,没有删除的字母。

如果当前字母是 B,且栈顶为 A,那么这两个字母都可以删除。同理,如果当前字母是 D,且栈顶为 C,那么这两个字母都可以删除。

否则,把当前字母入栈。

class Solution:
    def minLength(self, s: str) -> int:
        st = []
        for c in s:
            if st and (c == 'B' and st[-1] == 'A' or c == 'D' and st[-1] == 'C'):
                st.pop()
            else:
                st.append(c)
        return len(st)	

时间复杂度:O(n)

2697. 字典序最小回文串

难度简单1

给你一个由 小写英文字母 组成的字符串 s ,你可以对其执行一些操作。在一步操作中,你可以用其他小写英文字母 替换 s 中的一个字符。

请你执行 尽可能少的操作 ,使 s 变成一个 回文串 。如果执行 最少 操作次数的方案不止一种,则只需选取 字典序最小 的方案。

对于两个长度相同的字符串 ab ,在 ab 出现不同的第一个位置,如果该位置上 a 中对应字母比 b 中对应字母在字母表中出现顺序更早,则认为 a 的字典序比 b 的字典序要小。

返回最终的回文字符串。

示例 1:

输入:s = "egcfe"
输出:"efcfe"
解释:将 "egcfe" 变成回文字符串的最小操作次数为 1 ,修改 1 次得到的字典序最小回文字符串是 "efcfe",只需将 'g' 改为 'f' 。

示例 2:

输入:s = "abcd"
输出:"abba"
解释:将 "abcd" 变成回文字符串的最小操作次数为 2 ,修改 2 次得到的字典序最小回文字符串是 "abba" 。

示例 3:

输入:s = "seven"
输出:"neven"
解释:将 "seven" 变成回文字符串的最小操作次数为 1 ,修改 1 次得到的字典序最小回文字符串是 "neven" 。

提示:

  • 1 <= s.length <= 1000
  • s 仅由小写英文字母组成

双指针

采用双指针法,对字符串s遍历即可,这个操作次数的记录好像没啥用,字符串在python中不可修改,要记得先将其转化为列表list即可


对于两个中心对称的字母 x = s[i]y = s[n-1-i],如果 x != y,那么只需要修改一次,就可以让这两个字母相同: 把 x 改成 y 或者把 y 改成 x。

  • 如果 x > y,那么把 x 修改成 y 更好,这样字典序更小
  • 如果 x < y,那么把 y 修改成 x 更好,这样字典序更小
class Solution:
    def makeSmallestPalindrome(self, s: str) -> str:
        # 字符串在python中不可修改,要记得先将其转化为列表list即可
        n = len(s)
        if n == 1:
            return s
        s = list(s)
        cnt = 0
        low = 0
        high = n - 1
        while low <= high:
            if s[low] == s[high]:
                low += 1
                high -= 1
            else:
                if s[low] < s[high]:
                    s[high] = s[low]
                else:
                    s[low] = s[high]
                cnt += 1
                low += 1
                high -= 1
        return "".join(s)

时间复杂度:O(n)

2698. 求一个整数的惩罚数

难度中等6

给你一个正整数 n ,请你返回 n惩罚数

n惩罚数 定义为所有满足以下条件 i 的数的平方和:

  • 1 <= i <= n
  • i * i 的十进制表示的字符串可以分割成若干连续子字符串,且这些子字符串对应的整数值之和等于 i

示例 1:

输入:n = 10
输出:182
解释:总共有 3 个整数 i 满足要求:
- 1 ,因为 1 * 1 = 1
- 9 ,因为 9 * 9 = 81 ,且 81 可以分割成 8 + 1 。
- 10 ,因为 10 * 10 = 100 ,且 100 可以分割成 10 + 0 。
因此,10 的惩罚数为 1 + 81 + 100 = 182

示例 2:

输入:n = 37
输出:1478
解释:总共有 4 个整数 i 满足要求:
- 1 ,因为 1 * 1 = 1
- 9 ,因为 9 * 9 = 81 ,且 81 可以分割成 8 + 1 。
- 10 ,因为 10 * 10 = 100 ,且 100 可以分割成 10 + 0 。
- 36 ,因为 36 * 36 = 1296 ,且 1296 可以分割成 1 + 29 + 6 。
因此,37 的惩罚数为 1 + 81 + 100 + 1296 = 1478

提示:

  • 1 <= n <= 1000

模拟(枚举 + DFS)

class Solution {
    public int punishmentNumber(int n) {
        int ans = 0;
        for(int i = 1; i <= n; i++){
            String s = String.valueOf(i * i);
            if(dfs(s, i, 0, 0)){
                ans += i * i;
            }
        }
        return ans;
    }
	// 如1296,dfs枚举所有分割情况
    public boolean dfs(String s, int num, int i, int tot){
        if(i == s.length()){
            return tot == num ? true : false;
        }
        boolean ans = false;
        int j = i;
        while(j < s.length() && !ans){
            j += 1;
            int diff = Integer.valueOf(s.substring(i, j));
            if(tot + diff > num) break;
            ans |= dfs(s, num, j, tot + diff);
        }
        return ans;
    }
}

时间复杂度:

预处理(打表) + DFS

class Solution {
    // 判断 [1,1000] 的每个数字 i 是否符合要求,并预处理 [1,i] 内的符合要求的数字和 preSum。
    private static final int[] PRE_SUM = new int[1001];
    static {
        for (int i = 1; i <= 1000; i++) {
            var s = Integer.toString(i * i).toCharArray();
            PRE_SUM[i] = PRE_SUM[i - 1] + (dfs(s, i, 0, 0) ? i * i : 0);
        }
    }

    public int punishmentNumber(int n) {
        return PRE_SUM[n];
    }

    // 分割回文串 131. 分割回文串
    private static boolean dfs(char[] s, int i, int p, int sum){
        if(p == s.length) // 递归终点
            return sum == i; // i 符合要求
        int x = 0;
        for(int j = p; j < s.length; j++){ // 从 s[p] 到 s[j] 组成的子串
            x = x * 10 + s[j] - '0'; // 对应的整数值
            if(dfs(s, i, j+1, sum+x))
                return true;
        }
        return false;
    }
}

2699. 修改图中的边权

难度困难16

给你一个 n 个节点的 无向带权连通 图,节点编号为 0n - 1 ,再给你一个整数数组 edges ,其中 edges[i] = [ai, bi, wi] 表示节点 aibi 之间有一条边权为 wi 的边。

部分边的边权为 -1wi = -1),其他边的边权都为 数(wi > 0)。

你需要将所有边权为 -1 的边都修改为范围 [1, 2 * 109] 中的 正整数 ,使得从节点 source 到节点 destination最短距离 为整数 target 。如果有 多种 修改方案可以使 sourcedestination 之间的最短距离等于 target ,你可以返回任意一种方案。

如果存在使 sourcedestination 最短距离为 target 的方案,请你按任意顺序返回包含所有边的数组(包括未修改边权的边)。如果不存在这样的方案,请你返回一个 空数组

**注意:**你不能修改一开始边权为正数的边。

示例 1:

img

输入:n = 5, edges = [[4,1,-1],[2,0,-1],[0,3,-1],[4,3,-1]], source = 0, destination = 1, target = 5
输出:[[4,1,1],[2,0,1],[0,3,3],[4,3,1]]
解释:上图展示了一个满足题意的修改方案,从 0 到 1 的最短距离为 5 。

示例 2:

img

输入:n = 3, edges = [[0,1,-1],[0,2,5]], source = 0, destination = 2, target = 6
输出:[]
解释:上图是一开始的图。没有办法通过修改边权为 -1 的边,使得 0 到 2 的最短距离等于 6 ,所以返回一个空数组。

示例 3:

img

输入:n = 4, edges = [[1,0,4],[1,2,3],[2,3,5],[0,3,-1]], source = 0, destination = 2, target = 6
输出:[[1,0,4],[1,2,3],[2,3,5],[0,3,1]]
解释:上图展示了一个满足题意的修改方案,从 0 到 2 的最短距离为 6 。

提示:

  • 1 <= n <= 100
  • 1 <= edges.length <= n * (n - 1) / 2
  • edges[i].length == 3
  • 0 <= ai, bi < n
  • wi = -1 或者 1 <= wi <= 107
  • ai != bi
  • 0 <= source, destination < n
  • source != destination
  • 1 <= target <= 109
  • 输入的图是连通图,且没有自环和重边。

两次Dijkstra

题解:https://leetcode.cn/problems/modify-graph-edge-weights/solution/xiang-xi-fen-xi-liang-ci-dijkstrachou-mi-gv1m/

class Solution {
    public int[][] modifiedGraphEdges(int n, int[][] edges, int source, int destination, int target) {
        List<int[]> g[] = new ArrayList[n];
        Arrays.setAll(g, e -> new ArrayList<>());
        for (int i = 0; i < edges.length; i++) {
            int x = edges[i][0], y = edges[i][1];
            g[x].add(new int[]{y, i});
            g[y].add(new int[]{x, i}); // 建图,额外记录边的编号
        }

        var dis = new int[n][2];
        for (int i = 0; i < n; i++)
            if (i != source)
                dis[i][0] = dis[i][1] = Integer.MAX_VALUE;

        dijkstra(g, edges, destination, dis, 0, 0);
        int delta = target - dis[destination][0];
        if (delta < 0) // -1 全改为 1 时,最短路比 target 还大
            return new int[][]{};

        dijkstra(g, edges, destination, dis, delta, 1);
        if (dis[destination][1] < target) // 最短路无法再变大,无法达到 target
            return new int[][]{};

        for (var e : edges)
            if (e[2] == -1) // 剩余没修改的边全部改成 1
                e[2] = 1;
        return edges;
    }

    // 朴素 Dijkstra 算法
    // 这里 k 表示第一次/第二次
    private void dijkstra(List<int[]> g[], int[][] edges, int destination, int[][] dis, int delta, int k) {
        int n = g.length;
        var vis = new boolean[n];
        for (; ; ) {
            // 找到当前最短路,去更新它的邻居的最短路
            // 根据数学归纳法,dis[x][k] 一定是最短路长度
            int x = -1;
            for (int i = 0; i < n; ++i)
                if (!vis[i] && (x < 0 || dis[i][k] < dis[x][k]))
                    x = i;
            if (x == destination) // 起点 source 到终点 destination 的最短路已确定
                return;
            vis[x] = true; // 标记,在后续的循环中无需反复更新 x 到其余点的最短路长度
            for (var e : g[x]) {
                int y = e[0], eid = e[1];
                int wt = edges[eid][2];
                if (wt == -1)
                    wt = 1; // -1 改成 1
                if (k == 1 && edges[eid][2] == -1) {
                    // 第二次 Dijkstra,改成 w
                    int w = delta + dis[y][0] - dis[x][1];
                    if (w > wt)
                        edges[eid][2] = wt = w; // 直接在 edges 上修改
                }
                // 更新最短路
                dis[y][k] = Math.min(dis[y][k], dis[x][k] + wt);
            }
        }
    }
}

wt = 1; // -1 改成 1
if (k == 1 && edges[eid][2] == -1) {
// 第二次 Dijkstra,改成 w
int w = delta + dis[y][0] - dis[x][1];
if (w > wt)
edges[eid][2] = wt = w; // 直接在 edges 上修改
}
// 更新最短路
dis[y][k] = Math.min(dis[y][k], dis[x][k] + wt);
}
}
}
}


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

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

相关文章

开放原子训练营(第三季)inBuilder低代码开发实验室之低代码浪潮已至

目录 、前言&#xff1a; 一、为什么选择它 二、小试牛刀 3.1设计源数据 3.2设计页面 3.3发布应用 四、总结 、前言&#xff1a; 当你还在沉浸于AI和大数据浪潮带来的影响时&#xff0c;另一种低代码或0代码的编程方式在市场流行&#xff0c;截止至2023年&#xff0c;低代码的浪…

浅浅谈谈ssm的那些事儿外加AOP和DI+DAO思想的理解和处理json数据的第三方工具

MyBatis 一级缓存 默认是打开的 SqlSession级别的缓存&#xff0c;同一个SqlSession的发起多次同构查询&#xff0c;会将数据保存在一级缓存中。 在sqlsession 中有一个数据结构 是map 结构&#xff0c; 这个区域就是一级缓存区域&#xff0c;一级缓存区域中的 key 是由 sql 语…

11.Mysql内核语句优化规则详解

MySQL性能调优 1. 条件化简1.1 移动不必要的括号1.2 常量传递1.3 移动没用的条件1.4 表达式计算1.5 常量表检测 2. 外连接消除3. 子查询MySQL内部优化规则3.1 子查询语法3.1.1 按返回的结果集区分子查询标量子查询行子查询列子查询表子查询 3.1.2 按与外层查询关系来区分子查询…

20230522打开cv1826的buildroot的内核的早期打印的功能

20230522打开cv1826的buildroot的内核的早期打印的功能 在CV1826的buildroot启动的时候&#xff0c;有些内核打印/printk显示不了。 大概在内核时间3-4s秒钟的前后&#xff0c;有一段内核打印丢失了&#xff01; 在CV1826的buildroot启动到uboot的时候&#xff0c;按ctrlC组合…

性能优化之思路和分析

、优化思路 尽可能减少首屏必须资源的体积尽可能提前首屏必须资源/接口的请求发起时机延后闲时预缓存非必要资源/请求 代码分离 https://webpack.docschina.org/guides/code-splitting/ 动态导入 https://webpack.docschina.org/guides/code-splitting/#dynamic-imports sp…

vector模拟

先来看看vector的源码&#xff0c;string没有看是因为string严格意义上来讲不属于STL。 源代码之间也是存在区别的&#xff0c;大同小异&#xff0c;可以去网上查如何下载STL的源码库。 先看看<vector>文件中的内容&#xff08;当做参考即可&#xff09;&#xff1a; 内容…

springboot服务端接口公网远程调试 - 实现HTTP服务监听【端口映射】

文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…

【分布式系统】分布式锁实现之Redis

锁有资源竞争问题就有一定有锁的存在&#xff0c;存储系统MySQL中&#xff0c;有锁机制保证数据并发访问。而编程语言层面Java中有JUC并发工具包来实现&#xff0c;那么锁解决的问题是什么&#xff1f;主要是在多线程环境下&#xff0c;对共享资源的互斥。从而保证数据一致性。…

SVG在前端中的常见应用

SVG在前端中的常见应用 一、svg标签1. svg2. g 二、描边属性三、模糊和阴影效果1. 模糊2. 阴影效果 四、线性渐变和径向渐变1. 线性渐变2. 径向渐变 五、绘制1. 内置形状元素2. 绘制矩形3. 绘制圆形4. 绘制椭圆5. 绘制线条6. 绘制多边形7. 绘制多线条8. 绘制文本9. 绘制路径 只…

【C/C++】动态内存管理/泛型编程

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

SQLlite教程(第一篇)

SQLlite教程(第一篇 SQLlite是什么?SQLlite工作原理是什么?SQLlite有什么功能和特性?使用SQLlite有哪些注意事项?附加资料 SQLlite是什么? SQLite&#xff0c;是一款轻型的数据库&#xff0c;是遵守ACID的关系型数据库管理系统&#xff0c;它包含在一个相对小的C库中。它是…

Mysql审核查询平台Archery部署

目录 1 Archery产品介绍2 基于docker搭建Archery2.1 系统环境2.2 安装 Docker2.2.1 安装 Docker Compose2.2.2 下载Archery2.2.3 安装并启动2.2.4 表结构初始化2.2.5 数据初始化2.2.6 创建管理用户2.2.7 退出重启2.2.8 日志查看和问题排查2.2.9 启动成功查看2.2.10 端口占用情况…

基于Maven的profiles多环境配置

一个项目通常都会有多个不同的运行环境&#xff0c;例如开发环境&#xff0c;测试环境、生产环境等。而不同环境的构建过程很可能是不同的&#xff0c;例如数据源配置、插件、以及依赖的版本等。每次将项目部署到不同的环境时&#xff0c;都需要修改相应的配置&#xff0c;这样…

day07_数组初识

数组的概述 数组就是用于存储数据的长度固定的容器&#xff0c;保证多个数据的数据类型要一致。 数组适合做一批同种类型数据的存储 数组中的元素可以是基本数据类型&#xff0c;也可以是引用数据类型。当元素是引用数据类型是&#xff0c;我们称为对象数组。 容器&#xff…

从0开始学C语言的个人心得笔记(10w字)

大学的计算机相关专业第一门教学的计算机语言就是c语言&#xff0c;很多大学生面对从未接触过的计算机语言&#xff0c;可能会觉得很难以上门&#xff0c;从而放弃学习c语言。这篇博客写的主要是个人学习C语言时候的知识总结点&#xff0c;不能保证全部是正确的&#xff0c;如有…

Kafka灵魂28问

第 1 题 Kafka 数据可靠性如何保证&#xff1f; 对于 kafka 来说&#xff0c;以下几个方面来保障消息分发的可靠性&#xff1a; 消息发送的可靠性保障(producer) 消息消费的可靠性保障(consumer) Kafka 集群的可靠性保障&#xff08;Broker&#xff09; 生产者 目前生产者…

Leetcode每日一题——“用队列实现栈”

各位CSDN的uu们你们好呀&#xff0c;好久没有更新本专栏啦&#xff0c;甚是想念&#xff01;&#xff01;&#xff01;今天&#xff0c;小雅兰的学习内容是用队列实现栈&#xff0c;下面&#xff0c;让我们进入Leetcode的世界吧&#xff01;&#xff01;&#xff01; 这是小雅兰…

本地 docker 发布 java 项目,连接本地 redis 配置

1、本地项目 install 相应的 jar 包到 target 目录下&#xff0c;jar 包的路径步骤 2 要填写 2、项目根目录下创建 Dockerfile 文件 # 使用官方的 Java 11 镜像作为基础镜像 FROM openjdk:11-jdk# 设置工作目录 WORKDIR /app# 复制应用程序 JAR 文件到镜像中的 /app 目录下 C…

用LangChain实现一个ChatBlog

文章目录 前言环境一、构建知识库二、将知识库向量化三、召回四、利用LLM做阅读理解五、效果总结 前言 通过本文, 你将学会如何使用langchain来构建一个自己的知识库问答 其实大多数类chatpdf产品的原理都差不多, 我将其简单粗暴地分为以下四步: 构建知识库将知识库向量化召回…

vue diff算法与虚拟dom知识整理(11) 书写patch父级新旧为同一节点 子节点与文字交换逻辑实现

上文我们简单描述了patch处理同一节点的大体逻辑 这次 我们就来看一下text替换的情况 我们更改案例入口文件 src下的 index.js 代码如下 import h from "./snabbdom/h"; import patch from "./snabbdom/patch";const container document.getElementById(…