
题目大意
给定只包含小写字母和 ? 的字符串 s,把所有 ? 替换成小写字母,使得最终字符串中不存在两个相邻且相同的字符。
解题思路
核心结论:每个位置最多只需要考虑左右两个邻居。
- 从左到右扫描,遇到
?就处理; - 对
a~z依次尝试,只要和左边已确定的字符、右边的字符都不同,就选它; - 因为左右各最多占用 1 个字母,26 个字母里最多排除 2 个,必然存在可行解,且最多试 3 次就能找到,所以不需要回溯。
两个容易踩的坑:
- 边界越界 :
i == 0时没有左邻居,i == n - 1时没有右邻居,需要用短路||保护; - 右侧还是
?:由于是从左往右处理,右边可能尚未处理。但?不等于任何小写字母,所以判断天然成立,不需要特判。
参考代码(Java)
class Solution {
public String modifyString(String s) {
char[] arr = s.toCharArray();
int n = arr.length;
for (int i = 0; i < n; i++) {
if (arr[i] == '?') {
for (char c = 'a'; c <= 'z'; c++) {
// 与左邻居不同(若存在),且与右邻居不同(若存在)
if ((i == 0 || arr[i - 1] != c) && (i == n - 1 || arr[i + 1] != c)) {
arr[i] = c;
break;
}
}
}
}
return new String(arr);
}
}
复杂度
- 时间复杂度:O(n) 。每个
?最多枚举 3 次,视为常数,整体线性。 - 空间复杂度:O(n) (Java 字符串不可变,需转成
char[];若语言字符串可变则为 O(1))。
举例验证
以 s = "?zs" 为例:i = 0 时左无邻居,右侧是 z,枚举到 a 即满足,结果为 "azs"。
再如 s = "ubv?w":? 左为 v、右为 w,a 可用,结果为 "ubvaw"。