AcWing 4122.字符串转换

原题链接:AcWing 4122.字符串转换
题目来源:夏季每日一题2023

给定一个由小写字母构成的字符串 S

再给定一个由若干个各不相同的小写字母按字典序排序构成的字符串 F

现在,你可以对字符串 S 进行字符转换操作。

每次选中其中一个字符(即某个小写字母),将其转换为一个按照字母顺序与其相邻(上一个或下一个)的小写字母。

例如,c 可以转换为 b 或 d 。

额外的,我们将按照循环顺序考虑字母,即我们认为 a 的上一个字母为 z,z 的下一个字母为 a。

请问,至少需要进行多少次操作,可以使得字符串 S 中的每个字母都出现在字符串 F 中。

输入格式
第一行包含整数 T ,表示共有 T 组测试数据。

每组数据第一行包含一个字符串 S

第二行包含一个字符串 F

输出格式
每组数据输出一个结果,每个结果占一行。

结果表示为 Case #x: y ,其中 x 为组别编号(从 1 开始),y 为最少操作次数。

数据范围

  • 1≤T≤100,
  • 1≤|S|≤105,
  • 1≤|F|≤26。

输入样例1:

2
abcd
a
pppp
p

输出样例1:

Case #1: 6
Case #2: 0

输入样例2:

3
pqrst
ou
abd
abd
aaaaaaaaaaaaaaab
aceg

输出样例2:

Case #1: 9
Case #2: 0
Case #3: 1

时/空限制: 3s / 64MB




方法一:预处理+枚举

思路:

首先分析时间复杂度:
最多有100轮测试,每个测试里面S最多有105次个字符,因此一运行需要计算大概107次,再考虑到如果在循环中处理每个字母,需要再乘以26,大约就是2.6 * 108次,本题的时间限制是3秒,因此时间都是够用的。时间复杂度控制在O(n),或者O(n)*26 都是可以的

先预处理,在循环外对每个字母可以先计算最小步骤,这样可以一下子降低时间复杂度到O(n)

C++ 代码实现:

#include 
#include 
#include 
using namespace std;

const int maxn = 1e5 + 10, M = 30;

int t, cnt[M];  // cnt记录每个字母转换需要的最小步骤
char s[maxn], f[M];
bool st[M]; // 记录在f中出现的字母

int main(){
    scanf("%d", &t);
    for(int cases = 1; cases <= t; cases ++ ){
        scanf("%s%s", s, f);
        
        // st初始化
        memset(st, 0, sizeof st);
        
        // 预处理 记录在f中出现的字母
        for(int i = 0; f[i]; i ++ ){
            st[f[i] - 'a'] = true;
        }
        
        // 计算每个字母需要转换的最小步骤
        for(int i = 0; i < 26; i ++ ){
            int l = 0, r = 0;
            
            while(!st[(i - l + 26) % 26]) l ++ ; // 往左
            while(!st[(i + r) % 26]) r ++ ; // 向右
            
            cnt[i] = min(l, r);    // 存最小步骤
        }
            
        // 有独立性 每个字母都取最小 使得结果最小
        int ans = 0;
        for(int i = 0; s[i]; i ++ )
            ans += cnt[s[i] - 'a'];
        
        printf("Case #%d: %d\n", cases, ans);
    }
    
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n), 采用了预处理
  • 空间复杂度:O(1), st[]和cnt[]存的都是26个字母的信息

你可能感兴趣的:(每日一题,算法)