#P3891. 第1题-大写迁移
-
ID: 3255
Tried: 14
Accepted: 6
Difficulty: 2
所属公司 :
美团
时间 :2025年10月11日-算法岗
-
算法标签>模拟
第1题-大写迁移
解题思路
题意:给定只含大小写字母的字符串 s
(下标从 1 开始),维护计数器 x=1
。按 i=1..n
顺序进行:
- 若
i+x ≤ n
且s[i+x]
为大写字母,则把s[i+x]
改成小写,并令x+=1
;同时若s[i]
为小写则把s[i]
改成大写。 - 否则本次不做任何修改。输出最终字符串。
做法:模拟 / 双指针
用 0 下标实现更方便。遍历位置 i
,动态维护 x
,用另一个位置 j=i+x
(相当于第二个指针)。若 j
在范围内且 s[j]
是大写,则按规则修改 s[j]
、提升 x
,并把 s[i]
在需要时改成大写。整个过程只前进一次,所有操作都可在原串上完成。
核心要点
- 使用数组(字符列表)就地修改,避免反复构造新串。
- 每次成功触发操作都会使
x
增加 1,因此j=i+x
单调增加,整体只会检查与修改每个位置常数次,保证线性复杂度。
复杂度分析
- 时间复杂度:
O(n)
,每个位置至多被访问/修改常数次。 - 空间复杂度:
O(1)
(除字符数组外不需要额外空间)。
代码实现
Python
# 题面功能封装在外部函数里
def solve(n, s):
# 转为列表以便就地修改
a = list(s)
x = 1 # 计数器
for i in range(n): # i 为 0-based
j = i + x # 对应题意中的 i+x
# 判断是否满足触发条件:j 在范围内且 a[j] 为大写
if j < n and 'A' <= a[j] <= 'Z':
a[j] = a[j].lower() # s[i+x] 改小写
x += 1 # x 增加 1
# 若 s[i] 是小写则改为大写
if 'a' <= a[i] <= 'z':
a[i] = a[i].upper()
return ''.join(a)
if __name__ == "__main__":
import sys
data = sys.stdin.read().strip().split()
n = int(data[0])
s = data[1]
print(solve(n, s))
Java
import java.util.*;
// ACM 风格,类名固定为 Main
public class Main {
// 题面功能在外部函数里
public static String solve(int n, String s) {
char[] a = s.toCharArray();
int x = 1; // 计数器
for (int i = 0; i < n; i++) {
int j = i + x; // 对应题意中的 i+x
// 满足条件:j 合法且 a[j] 为大写
if (j < n && Character.isUpperCase(a[j])) {
a[j] = Character.toLowerCase(a[j]); // 改小写
x++; // x 自增
// 若 a[i] 为小写,则改为大写
if (Character.isLowerCase(a[i])) {
a[i] = Character.toUpperCase(a[i]);
}
}
}
return new String(a);
}
public static void main(String[] args) {
// 默认输入数据规模可用 Scanner
Scanner sc = new Scanner(System.in);
int n = Integer.parseInt(sc.next());
String s = sc.next();
System.out.print(solve(n, s));
sc.close();
}
}
C++
#include <bits/stdc++.h>
using namespace std;
// 题面功能在外部函数里
string solve(int n, string s) {
int x = 1; // 计数器
for (int i = 0; i < n; ++i) {
int j = i + x; // 对应题意中的 i+x
// 若 j 在范围内且 s[j] 为大写,则触发本次修改
if (j < n && isupper(static_cast<unsigned char>(s[j]))) {
s[j] = tolower(static_cast<unsigned char>(s[j])); // 改小写
x++; // x 自增
// 若 s[i] 为小写,则改为大写
if (islower(static_cast<unsigned char>(s[i]))) {
s[i] = toupper(static_cast<unsigned char>(s[i]));
}
}
}
return s;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
string s;
if (!(cin >> n)) return 0;
cin >> s;
cout << solve(n, s);
return 0;
}
题目内容
给定一个长度为 n 、由大小写字母组成的字符串 s (下标从 1 开始)。存在一个计数器 x ,初始 x=1 。你需要按下标从小到大的顺序,依次对每个下标 i 执行如下操作:
- 若 i+x≤n 且 si+x 为大写字母,则将 si+x 修改为小写字母,然后将增加 1 ;同时,若 si 为小写字母,则将 si 修改为大写字母。若不满足上述条件,则本次不进行任何修改。
请输出全部操作结束后的字符串。
输入描述
第一行输入一个整数 n(1≦n≦2×105) ,表示字符串长度。
第二行输入一个长度为 n 、仅由大小写字母组成的字符串 s 。
输出描述
在一行上输出一个长度为 n 的字符串,表示全部操作结束后的结果。
样例1
输入
4
abcX
输出
abCx
说明
在这组样例中:
-
初始 x=1 。当 i=1,2 时 i+x 对应的字符均不满足大写当 i=3 时,i+x=4 且 s4=′X′ 为大写,故将其改为小写 ′x′ 灭 增加为 2 ;同时 s3=′c’ 为小写,改为大写 ′C′;
-
其他位置不触发条件,不进行修改,最终得到 "abCx" 。
样例2
输入
6
aABCDe
输出
AABcDe
样例3
输入
5
AbCdE
输出
ABCde