Easy
题目描述
给你一个由数字和 ‘#’ 组成的字符串 s,你需要将 s 映射为英文小写字母,具体规则如下:
- 字符(‘a’ 到 ‘i’)分别用(‘1’ 到 ‘9’)表示。
- 字符(‘j’ 到 ‘z’)分别用(‘10#’ 到 ‘26#’)表示。
返回映射之后形成的新字符串。
题目数据保证映射始终唯一。
示例 1:
输入:s = "10#11#12"
输出:"jkab"
解释:"j" -> "10#" , "k" -> "11#" , "a" -> "1" , "b" -> "2"。
示例 2:
输入:s = "1326#"
输出:"acz"
提示:
- 1 <= s.length <= 1000
- s 只含有数字和字符 ‘#’。
- s 是一个有效字符串,映射总是存在。
解题思路
这道题的关键是理解编码规则:
- ‘a’-‘i’ 对应 ‘1’-‘9’
- ‘j’-‘z’ 对应 ‘10#’-‘26#’
有两种常见解法:
方法一:从右到左扫描(推荐) 从字符串末尾开始扫描,每次检查当前位置往后2位是否是’#’:
- 如果是’#’,则当前位置和前一位组成两位数字(如"10#")
- 如果不是’#’,则当前位置是单个数字
这种方法的优势是避免了向前看的复杂性,因为’#‘总是在两位数的末尾。
方法二:从左到右扫描 从左到右扫描,需要向前看2位判断是否有’#’:
- 如果当前位置+2是’#’,处理两位数
- 否则处理单位数
两种方法时间复杂度相同,但从右到左的方法实现更简洁。
核心思路是正确识别编码模式,然后将数字转换为对应的字母:数字n对应第n个字母,即’a’+n-1。
代码实现
class Solution {
public:
string freqAlphabets(string s) {
string result = "";
int i = s.length() - 1;
while (i >= 0) {
if (i >= 2 && s[i] == '#') {
// 处理两位数字
int num = (s[i-2] - '0') * 10 + (s[i-1] - '0');
result = char('a' + num - 1) + result;
i -= 3;
} else {
// 处理单位数字
int num = s[i] - '0';
result = char('a' + num - 1) + result;
i--;
}
}
return result;
}
};
class Solution:
def freqAlphabets(self, s: str) -> str:
result = []
i = len(s) - 1
while i >= 0:
if i >= 2 and s[i] == '#':
# 处理两位数字
num = int(s[i-2:i])
result.append(chr(ord('a') + num - 1))
i -= 3
else:
# 处理单位数字
num = int(s[i])
result.append(chr(ord('a') + num - 1))
i -= 1
return ''.join(reversed(result))
public class Solution {
public string FreqAlphabets(string s) {
var result = new StringBuilder();
int i = s.Length - 1;
while (i >= 0) {
if (i >= 2 && s[i] == '#') {
// 处理两位数字
int num = (s[i-2] - '0') * 10 + (s[i-1] - '0');
result.Insert(0, (char)('a' + num - 1));
i -= 3;
} else {
// 处理单位数字
int num = s[i] - '0';
result.Insert(0, (char)('a' + num - 1));
i--;
}
}
return result.ToString();
}
}
var freqAlphabets = function(s) {
let result = "";
let i = s.length - 1;
while (i >= 0) {
if (i >= 2 && s[i]
复杂度分析
| 复杂度 | 大O表示法 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 需要遍历字符串一次,每个字符最多访问一次 |
| 空间复杂度 | O(n) | 需要额外空间存储结果字符串 |