12.最大UCC子串计算<字节青训营-困难题>

题解:‍‬‬‌‌‌⁠⁠‍‌‌‬‌‬⁠⁠12. 最大UCC子串计算 - 飞书云文档

1.题目

问题描述

小S有一个由字符 'U' 和 'C' 组成的字符串 SS,并希望在编辑距离不超过给定值 mm 的条件下,尽可能多地在字符串中找到 "UCC" 子串。

编辑距离定义为将字符串 SS 转化为其他字符串时所需的最少编辑操作次数。允许的每次编辑操作是插入、删除或替换单个字符。你需要计算在给定的编辑距离限制 mm 下,能够包含最多 "UCC" 子串的字符串可能包含多少个这样的子串。

例如,对于字符串"UCUUCCCCC"和编辑距离限制m = 3,可以通过编辑字符串生成最多包含3个"UCC"子串的序列。

约束条件:

  • 字符串长度不超过1000

测试样例

样例1:

输入:m = 3,s = "UCUUCCCCC"

输出:3

样例2:

输入:m = 6,s = "U"

输出:2

样例3:

输入:m = 2,s = "UCCUUU"

输出:2

解释

样例1:可以将字符串修改为 "UCCUCCUCC"(2 次替换操作,不超过给定值 m = 3),包含 3 个 "UCC" 子串。

样例2:后面插入 5 个字符 "CCUCC"(5 次插入操作,不超过给定值 m = 6),可以将字符串修改为 "UCCUCC",包含 2 个 "UCC" 子串。

样例3:替换最后 2 个字符,可以将字符串修改为 "UCCUCC",包含 2 个 "UCC" 子串。

2.思路

  • 考虑下编辑距离的三种操作:插入,删除,修改,我们要得到更多的$$UC$$串,插入是最优的操作,删除是完全不操作的, 替换操作完全可以由插入操作代替,解释下为什么
  • UUC为例,替换操作会改变成UCC, 而插入操作会得到UUCC,多一个字符对构造新的UCC串更优, 比如此时m=3
    • 采取替换操作只能得到1个UUC -> UCC -> UCCUC
    • 而插入可以得到两个UUC ->UUCC -> UCCUCC
    • 删除操作完全对答案没有贡献
  • 考虑如何操作最优,由上面可知,所有操作均采取插入。那么已经是UCC的串不需要操作,直接记录, 后面插入也不对已经是UCC的串进行操作,因为对这些进行操作完全对答案不优
  • 考虑只需要插入一次可以构成UCC的情况有哪些?
    • U*C*C的前后都可以,那么只要是UC我们就可以花费代价1让ans加一
    • CC在 第一个C前面, 那么只要是CC就行
    • 字符只能使用一次,所有用后要记录字符的使用状态
  • 剩下的字符都需要进行两次操作才能得到UCC
  • 我们可以使用变量$$cnt$$记录当前已经操作的字符数量,$$n-cn$$就是剩下需要操作两次的字符数量

3.代码

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int solution(int m, std::string s) {
    // PLEASE DO NOT MODIFY THE FUNCTION SIGNATURE
    // write code here
    int n = s.length();
    vector<bool> use(n, false); //来记录每个位置是否被“插入操作”使用过(每个字符只能使用一次)
    int cnt = 0; // 记录已经操作的字符数
    int ans = 0; // 记录可以插入的 "UCC" 子串的数量

    // 第一步:处理已经是 "UCC" 的子串
    // 遍历字符串,从第3个字符开始,检查每一个 3 字符子串是否是 "UCC"
    for (int i = 2; i < n; i++) {
      string t = s.substr(i - 2, 3);
      if (t == "UCC") {
        use[i] = use[i - 1] = use[i - 2] = true;
        cnt += 3; // 更新已经操作的字符数
        ans++; // 插入了一个 "UCC",计数加一
      }
    }
    // 第二步:处理 "UC" 和 "CC" 的插入
    // 遍历字符串,检查 "UC" 和 "CC" 是否可以插入
    for (int i = 1; i < n; i++) {
      string t = s.substr(i - 1, 2);
      // 如果当前字符对未被使用过,且 m > 0,可以进行插入
      if (!use[i] && !use[i - 1] && m > 0) {
        if (t == "UC" || t == "CC") {
          use[i] = use[i - 1] = true;
          cnt += 2; //更新已经操作的字符数
          ans++; 
          m--;
        }
      }
    }

    // 第三步:处理剩余的字符
    // 每两次操作才能插入一个UCC(即单个字符插入需要两次操作),
    // 可以使用剩余的 m 次操作尽可能多地插入字符
    ans += min(m / 2, n - cnt);
    m -= min(m / 2, n - cnt) * 2;

    // 第四步:处理剩余的 m 次操作
    // 如果 m 大于 2,则每三次操作可以插入一个 "UCC" 子串
    if (m > 2) {
      ans += m / 3;
    }
    return ans; // Placeholder
}
int main() {
    std::cout << (solution(3, "UCUUCCCCC") == 3) << std::endl;
    std::cout << (solution(6, "U") == 2) << std::endl;
    std::cout << (solution(2, "UCCUUU") == 2) << std::endl;
    return 0;
}

方法二:两次动规

def solution(m: int, s: str) -> int:
    # write code here
    n = len(s)
    dp = [[-1] * (m + 1) for _ in range(n + 1)]  # dp[i][e]:前i个字符编辑e次得到的’UCC'子串数量
    dp[0][0] = 0 

    # 第一次动态规划
    # 计算从每个字符开始,为了匹配 "UCC" 产生的最小编辑距离和匹配成功时的长度
    # 每个字符的计算过程都是dp
    match_info = [[] for _ in range(n)]  # match_info[i] = 从s[i]开始,匹配“UCC”的(最小编辑距离,匹配成功时的长度) 
    for i in range(n):
        max_len = min(n - i, 3 + m)  # 从当前字符s[i]开始,匹配成功时可能达到的最大长度
        # 从当前字符s[i]开始,匹配 "UCC" 的最小编辑距离
        dp_match = [[float('inf')] * (max_len + 1) for _ in range(4)] 
        dp_match[0][0] = 0
        for p in range(4):  # 从s[i]开始匹配"UCC" 的进度:‘’->‘U'->'UC'->'UCC’
            for q in range(max_len + 1):  # 匹配过程中划过的长度 = 0,1,...,max_len
                if dp_match[p][q] > m:  # 编辑次数用完了
                    continue
                if p < 3 and q < max_len:  # 保留/替换
                    cost = 0 if s[i + q] == 'UCC'[p] else 1
                    dp_match[p + 1][q + 1] = min(dp_match[p + 1][q + 1], dp_match[p][q] + cost)
                if p < 3:  # 插入
                    dp_match[p + 1][q] = min(dp_match[p + 1][q], dp_match[p][q] + 1)
                if q < max_len:  # 删除
                    dp_match[p][q + 1] = min(dp_match[p][q + 1], dp_match[p][q] + 1)
        # 统计
        for q in range(max_len + 1):
            c = dp_match[3][q]
            match_info[i].append((c, q))  # (编辑距离,匹配长度)

    # 主过程的动态规划:
    for i in range(n + 1):
        for e in range(m + 1):
            if dp[i][e] == -1:
                continue
            if i < n:  # 不尝试匹配 "UCC" --> 直接跳过/删除当前字符
                dp[i + 1][e] = max(dp[i + 1][e], dp[i][e])  # 保留
                if e + 1 <= m:  # 删除
                    dp[i + 1][e + 1] = max(dp[i + 1][e + 1], dp[i][e])            
            if i < n and match_info[i]: # 尝试匹配
                for c, l in match_info[i]:  # 从当前字符串开始匹配‘UCC’的(最小编辑距离,匹配成功时长度)
                    if e + c <= m and i + l <= n:
                        dp[i + l][e + c] = max(dp[i + l][e + c], dp[i][e] + 1)

    # 找到最大匹配数量
    max_substrings = 0
    for e in range(m + 1):
        max_substrings = max(max_substrings, dp[n][e])
    return max_substrings

if __name__ == '__main__':
    print(solution(m=3, s="UCUUCCCCC") == 3)
    print(solution(m=6, s="U") == 2)
    print(solution(m=2, s="UCCUUU") == 2)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Sentinel】初识Sentinel

目录 1.1.雪崩问题及解决方案 1.1.1.雪崩问题 1.1.2.超时处理 1.1.3.仓壁模式 1.1.4.断路器 1.1.5.限流 1.1.6.总结 1.2.服务保护技术对比 1.3.Sentinel介绍和安装 1.3.1.初识Sentinel 1.3.2.安装Sentinel 1.4.微服务整合Sentinel 1.1.雪崩问题及解决方案 1.1.1.…

[A-24][V-09]ARMv8/v9-SMMU工作场景与SMMU的虚拟化架构

ver0.1 [看前序文章有惊喜,关注W\X\G=Z+H=“浩瀚架构师”,可以解锁全部文章] 前言 我们在介绍ARM的内存体系的时候,行文中经常讲MMU比作PE-Cores的带刀护卫。按照这个逻辑,那么SMMU也可以称之为总线上各个Master(设备)的带刀护卫,利刃出鞘之后,任何驱动送过来的地址都…

WebRTC服务质量(10)- Pacer机制(02) RoundRobinPacketQueue

WebRTC服务质量&#xff08;01&#xff09;- Qos概述 WebRTC服务质量&#xff08;02&#xff09;- RTP协议 WebRTC服务质量&#xff08;03&#xff09;- RTCP协议 WebRTC服务质量&#xff08;04&#xff09;- 重传机制&#xff08;01) RTX NACK概述 WebRTC服务质量&#xff08;…

硬件设计-时钟振荡器

目录 摘要 壳式晶振 正常工作条件 摘要 本章主要介绍了晶振的分类、各项参数的意义、特点&#xff0c;同时也介绍了时钟抖动的成因、测量 方法、消除措施和典型滤波电路&#xff0c;使得我们可以正确地选择和使用晶振。 壳式晶振 如图 所示&#xff0c;壳式晶振的名字来源于…

Redis基础知识分享(含5种数据类型介绍+增删改查操作)

一、redis基本介绍 1.redis的启动 服务端启动 pythonubuntu:~$ redis-server客户端启动 pythonubuntu:~$ redis-cli <127.0.0.1:6379> exit pythonubuntu:~$ redis-cli --raw //(支持中文的启动方式) <127.0.0.1:6379> exit2.redis基本操作 ping发送给服务器…

sql字段值转字段

表alertlabel中记录变字段 如何用alertlabel表得到下面数据 实现的sql语句 select a.AlertID, (select Value from alertlabel where AlertIDa.AlertID and Labelhost) as host, (select Value from alertlabel where AlertIDa.AlertID and Labeljob) as job from (select …

llamafactory报错:双卡4090GPU,训练qwen2.5:7B、14B时报错GPU显存不足(out of memory),轻松搞定~~~

实际问题场景&#xff1a; 使用llamafactory进行微调qwen2.5 7B和14B的大模型时&#xff0c;会出现out of memory的报错。尝试使用降低batch_size&#xff08;原本是2&#xff0c;现在降到1&#xff09;的方式&#xff0c;可以让qwen2.5:7B跑起来&#xff0c;但时不时会不稳定…

【hackmyvm】hacked靶机wp

tags: HMVrootkitDiamorphine Type: wp 1. 基本信息^toc 文章目录 1. 基本信息^toc2. 信息收集2.1. 端口扫描2.2. 目录扫描2.3. 获取参数 3. 提权 靶机链接 https://hackmyvm.eu/machines/machine.php?vmHacked 作者 sml 难度 ⭐️⭐️⭐️⭐️️ 2. 信息收集 2.1. 端口扫描…

.NET平台用C#通过字节流动态操作Excel文件

在.NET开发中&#xff0c;通过字节流动态操作Excel文件提供了一种高效且灵活的方式处理数据。这种方法允许开发者直接在内存中创建、修改和保存Excel文档&#xff0c;无需依赖直接的文件储存、读取操作&#xff0c;从而提高了程序的性能和安全性。使用流技术处理Excel不仅简化了…

应用层1——C/S、P2P、DNS域名系统

目录 一、网络应用模型 1、C/S 2、p2p模型 二、域名解析系统DNS 1、为什么有DNS系统&#xff1f; 2、域名的特点 3、DNS域名系统原理 4、递归查询、迭代查询 5、常用的根域名与顶级域名 一、网络应用模型 1、C/S 客户/服务器模型 客户请求服务&#xff0c;服务器提供…

【疑难杂症】 HarmonyOS NEXT中Axios库的响应拦截器无法拦截424状态码怎么办?

今天在开发一个HarmonyOS NEXT的应用的时候&#xff0c;发现http接口如果返回的状态码是424时&#xff0c;我在axios中定义的拦截器失效了。直接走到了业务调用的catch中。 问题表现&#xff1a; 我的拦截器代码如下&#xff1a; 解决办法&#xff1a; 先说解决办法&#xff…

在Windows上读写Linux磁盘镜像的一种方法

背景 嵌入式开发中&#xff0c;经常会把系统的Linux磁盘镜像保存到Windows上&#xff0c;以便上传到网盘备份或发送给工厂&#xff0c;但是如果想读取/修改镜像中的某个文件&#xff0c;一般有2种方案&#xff1a; 直接访问 就是用虚拟磁盘软件将镜像文件挂载成磁盘&#xf…

ffmpeg之显示一个yuv照片

显示YUV图片的步骤 1.初始化SDL库 目的&#xff1a;确保SDL库正确初始化&#xff0c;以便可以使用其窗口、渲染和事件处理功能。操作&#xff1a;调用 SDL_Init(SDL_INIT_VIDEO) 来初始化SDL的视频子系统。 2.创建窗口用于显示YUV图像&#xff1a; 目的&#xff1a;创建一个…

Windows下播放文件作为麦克风声源的一种方式

近期测试一种外语的ASR识别成功率&#xff0c;样本素材是懂这门语言的同事录制的mp3文件。测试client端原本是从麦克风拾音生成媒体流的。 这样&#xff0c;就需要想办法把mp3文件转换为测试client的输入声音。物理方式上&#xff0c;可以用一根音频线&#xff0c;把电…

如何在网页端使用 IDE 高效地阅读 GitHub 源码?

如何在网页端使用 IDE 高效地阅读 GitHub 源码&#xff1f; 前言什么是 GitHub1s&#xff1f;使用 GitHub1s 阅读 browser-use 项目源码步骤 1: 打开 GitHub 项目页面步骤 2: 修改 URL 使用 GitHub1s步骤 3: 浏览文件结构步骤 4: 使用代码高亮和智能补全功能步骤 5: 快速跳转和…

Microsoft word@【标题样式】应用不生效(主要表现为在导航窗格不显示)

背景 随笔。Microsoft word 2013基础使用&#xff0c;仅做参考和积累。 问题 Microsoft word 2013&#xff0c;对段落标题文字应用【标题样式】不生效&#xff08;主要表现为在导航窗格不显示&#xff09;。 图1 图2 观察图1和图2&#xff0c;发现图1的文字在应用【标题一】样…

2021.12.28基于UDP同信的相关流程

作业 1、将TCP的CS模型再敲一遍 服务器 #include <myhead.h> #define PORT 8888 #define IP "192.168.124.123" int main(int argc, const char *argv[]) {//创建套接字//绑定本机IP和端口号//监听客户端请求//接收客户端连接请求//收发消息//创建套接字int…

OpenCV和PyQt的应用

1.创建一个 PyQt 应用程序&#xff0c;该应用程序能够&#xff1a; 使用 OpenCV 加载一张图像。在 PyQt 的窗口中显示这张图像。提供四个按钮&#xff08;QPushButton&#xff09;&#xff1a; 一个用于将图像转换为灰度图一个用于将图像恢复为原始彩色图一个用于将图像进行翻…

kibana启动报错:Invalid character in header content [“kbn-name“]

启动时候kibana报错&#xff1a; 打开 kibana配置文件&#xff0c;config/kibana.yml&#xff0c;配置上server.name即可&#xff0c;如下&#xff1a;

Pandas08

Pandas01 Pandas02 Pandas03 Pandas04 Pandas05 Pandas06 Pandas07 文章目录 内容回顾同期群分析1.1 同期群分析概念1.2 案例代码 数据分析报告数据分析工作内容数据分析简历说明用户生命周期标签1 什么是生命周期标签2 如何计算生命周期标签 内容回顾 TGI 偏好分析 TGI 目标…