“可达鸭杯”补题 J-字符魔法

话不多说,先上题目:
 

题目描述

小 Z 有一个只包含小写英文字母的字符串 S 。

小 Z 还会一种奇妙的字符魔法,每次使用魔法可以将字符串 S 中的一个字符改变成任意一个小写英文字母。

发动魔法非常耗费小 Z 的精力,因此他想知道,如果想让 S 中下标为 的字符都变成相同的小写字母,最少需要使用几次魔法。

小 Z 对这样的问题非常感兴趣,因此他会询问 m 次这样的问题。请注意,小 Z 只是进行询问,并不会真的使用魔法对字符串进行修改。

输入描述:

第一行两个整数 n,m分别表示字符串的长度和小 Z 询问的次数。

第二行一个长度为 n 的只包含小写英文字母的字符串 S。

接下来 m,每行两个整数 l,r,表示要将下标从 l​ 到 r 的字符都变成相同的。

输出描述:

共 m 行,每行一个整数,表示小 Z 最少使用的魔法次数。

本题数据范围 1≤n,m≤105,1≤l​≤r​≤n

接下来是解题正文:

一开始我是想暴力的写法,做一个cont[26]存每个l,r区间上的字节,然后再遍历一遍cont[26]找到其中的max,那么最后的答案就是 "r - l + 1 - max" //r-l+1是在选定区间上所有的字节数,然后再减去max就是最大相同字节数,剩下的就是要变换的字节,就是把其他所有字节变成区间上最多的字节。

这是我一开始提交的代码,很显然它TLE了。

那么这个思路肯定是行不通了,就让我们联系下学过的算法来优化下这串代码。

因为题目中给出了区间l,r的形式让我们求区间内不同字母数量,我们可以想到用前缀和的形式来优化算法。就是先把各个区间中字母总数用前缀和的形式统计出来,然后在给定的l,r区间内找出其中的max值,就可以达到优化算法的目的。

接下来,是用前缀和优化后的代码:

肉眼可见代码运行时间减少了太多,此时提交就莫有问题,可以放心不怕吃一发罚时。

接下来是对代码的讲解:

先做一个cont[26][N]的二维数组,前面26是存储的字母形式,a-z 就对应 0-25。然后第一个for循环先存储字符串S,因为后面前缀和要做j-1的操作,所以这边存储是做了i+1的操作目的是让cont从1开始,这样就不会出现0减1这种情况防止莫名のbug。然后就是一个前缀和求和形式,虽然是二维但并不是矩阵前缀和,因为前面26代表的只是字母是它下标存储的东西,所以还是用一维数组求前缀和形式正常写就行,不过要在前面加上一个0到25的for循环,意为将每个字母的一维前缀和都求一遍。所以说把这个二维数组当成一维就可以,前面的26用for循环代替,就是求26个从字母a到zの一维数组的前缀和。

然后就是输入区间l,r在区间内每个字母的总和就是cont[i][r] - cont[i][l-1],于是只要找26遍每个字母在区间的总和,用max函数找到其中字母最大值最后输出r-l+1-max就好了。

这样题目就结束了,我用我不专业的角度来分析下这两个代码的时间复杂度

首先第一段代码,在m次操作中对于l到r的范围遍历操作,然后在26个字母中再遍历找最大值,那么它的复杂度应该就是“m*(r-l) + 26*m ”当区间无限接近n时,那么复杂度就   ≈n^2 

那么它超时也在情理之中捏。

然后第二段代码,首先做前缀和复杂度有26n,然后再m次操作中每次取用是O(1)的复杂度,那么它的复杂度应该就是“26n+26m

所以,它就这么远超第一个代码的过掉了题目

声明 !!!博主对于时间复杂度分析并不专业,很有可能有错误,欢迎大家指出(手动爱心)!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

原神顶级高手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值