#P3343. 第1题-小美的字符串
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 180
            Accepted: 68
            Difficulty: 3
            
          
          
          
                       所属公司 : 
                              美团
                                
            
                        
              时间 :2025年8月9日-算法岗
                              
                      
          
 
- 
                        算法标签>模拟          
 
第1题-小美的字符串
解题思路
- 
操作并不是对字符串中的“区间位置”生效,而是对字母表中的一个字母区间生效(如
[a,c]),把所有出现的这些字母统一大小写转换。 - 
因此,我们不需要一遍遍扫描字符串;只要记录每个字母最近一次被“转成大写”的操作时间与最近一次被“转成小写”的操作时间即可。
 - 
设:
last_up[c]:字母c(0~25)最近一次被“转大写”的操作编号(没有则为 0)last_low[c]:字母c最近一次被“转小写”的操作编号(没有则为 0)
 - 
读入每个操作
[letter1, letter2](保证letter1 <= letter2),把这个闭区间内对应字母的last_up或last_low更新为该操作的编号i。- 注意:
op=1输入给的是小写范围,op=2输入给的是大写范围,但我们统一把端点转成小写来算索引即可。 
 - 注意:
 - 
全部操作读完后,逐个遍历原串字符
ch:- 
令
idx = tolower(ch) - 'a' - 
比较
last_up[idx]与last_low[idx]:- 若二者都为 0:该字母不受影响,保持原样
 - 否则谁时间戳更大就说明最后一次操作决定它是大写或小写
 
 
 - 
 - 
复杂度:每个操作最多更新 26 个字母,所以总计
O(m * 26 + n),对于约束m,n ≤ 2e5十分安全。 
代码实现
import sys
def main():
    # 读取输入并分割为列表,使用迭代器方便依次取值
    data = sys.stdin.read().strip().split()
    it = iter(data)
    # 读取 n(字符串长度)和 m(操作次数)
    n = int(next(it))
    m = int(next(it))
    # 原始字符串转成 list,方便后面修改
    s = list(next(it))
    # last_up[i]:字母 i(0~25)最后一次被转成大写的操作编号
    # last_low[i]:字母 i(0~25)最后一次被转成小写的操作编号
    last_up = [0] * 26
    last_low = [0] * 26
    # 处理 m 次操作
    for i in range(1, m + 1):
        op = int(next(it))  # 操作类型
        l1 = next(it)       # 左端字母
        l2 = next(it)       # 右端字母
        # 统一转成小写来计算字母在 0~25 的索引
        a = ord(l1.lower()) - ord('a')
        b = ord(l2.lower()) - ord('a')
        # 保证 a <= b
        if a > b:
            a, b = b, a
        if op == 1:
            # 将区间 [a, b] 的字母记录“最后一次转大写”的时间戳为当前操作编号 i
            for x in range(a, b + 1):
                last_up[x] = i
        else:
            # 将区间 [a, b] 的字母记录“最后一次转小写”的时间戳为当前操作编号 i
            for x in range(a, b + 1):
                last_low[x] = i
    res = []
    # 遍历原始字符串的每个字符
    for ch in s:
        idx = ord(ch.lower()) - ord('a')  # 找到字符对应的字母索引
        if 0 <= idx < 26:
            u = last_up[idx]   # 最后一次转大写的操作编号
            d = last_low[idx]  # 最后一次转小写的操作编号
            if u == 0 and d == 0:
                # 该字母从未被修改过,保持原样
                res.append(ch)
            elif u > d:
                # 最近一次修改是转大写
                res.append(ch.upper())
            else:
                # 最近一次修改是转小写
                res.append(ch.lower())
        else:
            # 非字母字符,直接保留
            res.append(ch)
    # 输出最终结果
    print(''.join(res))
if __name__ == "__main__":
    main()
        题目内容
小美有一个长度为n,仅由大小写英文字母组成的字符串s。小美将对字符串执行以下m次操作:
- 
当操作类型op=1且给定两个小写字母letter1,letter2(满足letter1≦letter2)时,将字符串中所有位于字母表中[letter1,letter2]的小写字母转换为对应的大写字母;
 - 
当操作类型op=2且给定两个大写字母letter1,letter2(满足letter1≦letter2)时,将字符串中所有位于字母表中[letter1,letter2]的大写字母转换为对应的小写字母。
 
输入描述
在一行上输入两个整数n,m(1≦n,m≦2×105),分别表示字符串长度和操作次数;
在一行上输入一个长度为n,仅由大小写英文字母组成的字符串s;
接下来m行,每行输入三个元素:整数op和两个字符letter1,letter2,满足:
- 若op=1,则letter1,letter2为小写字母,且letter1≦letter2;
 - 若op=2,则letter1,letter2为大写字母,且letter1≦letter2。
 
输出描述
输出执行完所有操作后得到的最终字符串。
样例1
输入
3 1
abc
1 a c
输出
ABC
说明
在此样例中,初始字符串"abc",将区间[a,c]的小写字母统一转换成大写,得到"ABC"。
样例2
输入
6 2
aAbBcC
1 a b
2 B C
输出
AAbbcc
说明
在此样例中,
- 第一次操作将字符串中所有满足字母表区间[a,b]所有小写字母的变为大写字母,得到"AABBcC";
 - 第二次操作将字符串中所有满足字母表区间[B,C]所有大写字母的变为小写字母,最终得到"AAbbcc"。