Article / 文章
LeetCode 第423题:从英文中重建数字
给你一个字符串 s ,其中包含字母顺序打乱的用英文单词表示的若干数字(0-9)。按 升序 返回原始的数字。
📖 文章摘要
本文详细解析LeetCode第423题“从英文中重建数字”,这是一道字符串处理和计数问题。文章提供了基于字符统计和规律匹配的解题思路,包含C#、Python、C++三种语言实现,配有详细的分析和性能对比。适合想要提升字符串处理能力的程序员。
核心知识点: 字符统计、贪心算法、字符串处理
难度等级: 中等
推荐人群: 具有基础算法知识的程序员
题目描述
给你一个字符串 s ,其中包含字母顺序打乱的用英文单词表示的若干数字(0-9)。按 升序 返回原始的数字。
示例
示例 1:
输入:s = "owoztneoer"
输出:"012"
示例 2:
输入:s = "fviefuro"
输出:"45"
提示
- 1 <= s.length <= 105
- s[i] 为 [“e”,“g”,“f”,“i”,“h”,“o”,“n”,“s”,“r”,“u”,“t”,“w”,“v”,“x”,“z”] 中的一个
- s 保证是一个符合题目要求的字符串
解题思路
本题的关键是找到每个数字的英文单词中的特殊字符,通过这些特殊字符来确定数字的出现次数。我们可以通过以下步骤解决:
-
观察每个数字的英文单词:
- zero: z唯一
- two: w唯一
- four: u唯一
- six: x唯一
- eight: g唯一
- one: o(去掉zero、two、four的o后)
- three: h(去掉eight的h后)
- five: f(去掉four的f后)
- seven: s(去掉six的s后)
- nine: i(去掉five、six、eight的i后)
-
按照上述顺序统计字符出现次数,逐个确定每个数字的出现次数。
图解思路
字符统计分析表
| 数字 | 特征字符 | 单词 | 说明 |
|---|---|---|---|
| 0 | z | zero | z只在zero中出现 |
| 2 | w | two | w只在two中出现 |
| 4 | u | four | u只在four中出现 |
| 6 | x | six | x只在six中出现 |
| 8 | g | eight | g只在eight中出现 |
| 3 | h | three | 去掉eight后的h |
| 5 | f | five | 去掉four后的f |
| 7 | s | seven | 去掉six后的s |
| 1 | o | one | 去掉zero/two/four后的o |
| 9 | i | nine | 最后剩余的i |
处理顺序表
| 步骤 | 处理数字 | 依据字符 | 后续处理 |
|---|---|---|---|
| 1 | 0,2,4,6,8 | z,w,u,x,g | 直接统计特征字符 |
| 2 | 3,5,7 | h,f,s | 减去之前数字的影响 |
| 3 | 1 | o | 减去0,2,4的影响 |
| 4 | 9 | i | 减去5,6,8的影响 |
代码实现
C# 实现
public class Solution {
public string OriginalDigits(string s) {
// 统计每个字符出现的次数
int[] count = new int[26];
foreach (char c in s) {
count[c - 'a']++;
}
// 统计每个数字出现的次数
int[] nums = new int[10];
// 根据唯一字符确定数字
nums[0] = count['z' - 'a']; // zero
nums[2] = count['w' - 'a']; // two
nums[4] = count['u' - 'a']; // four
nums[6] = count['x' - 'a']; // six
nums[8] = count['g' - 'a']; // eight
// 处理重叠字符
nums[3] = count['h' - 'a'] - nums[8]; // three - eight
nums[5] = count['f' - 'a'] - nums[4]; // five - four
nums[7] = count['s' - 'a'] - nums[6]; // seven - six
nums[1] = count['o' - 'a'] - nums[0] - nums[2] - nums[4]; // one - zero - two - four
nums[9] = count['i' - 'a'] - nums[5] - nums[6] - nums[8]; // nine - five - six - eight
// 构建结果字符串
StringBuilder result = new StringBuilder();
for (int i = 0; i < 10; i++) {
result.Append(new string((char)('0' + i), nums[i]));
}
return result.ToString();
}
}
Python 实现
class Solution:
def originalDigits(self, s: str) -> str:
# 统计字符出现次数
count = Counter(s)
# 统计每个数字出现的次数
nums = [0] * 10
# 根据唯一字符确定数字
nums[0] = count['z'] # zero
nums[2] = count['w'] # two
nums[4] = count['u'] # four
nums[6] = count['x'] # six
nums[8] = count['g'] # eight
# 处理重叠字符
nums[3] = count['h'] - nums[8] # three - eight
nums[5] = count['f'] - nums[4] # five - four
nums[7] = count['s'] - nums[6] # seven - six
nums[1] = count['o'] - nums[0] - nums[2] - nums[4] # one - zero - two - four
nums[9] = count['i'] - nums[5] - nums[6] - nums[8] # nine - five - six - eight
# 构建结果字符串
return ''.join(str(i) * nums[i] for i in range(10))
C++ 实现
class Solution {
public:
string originalDigits(string s) {
// 统计字符出现次数
vector<int> count(26, 0);
for (char c : s) {
count[c - 'a']++;
}
// 统计每个数字出现的次数
vector<int> nums(10, 0);
// 根据唯一字符确定数字
nums[0] = count['z' - 'a']; // zero
nums[2] = count['w' - 'a']; // two
nums[4] = count['u' - 'a']; // four
nums[6] = count['x' - 'a']; // six
nums[8] = count['g' - 'a']; // eight
// 处理重叠字符
nums[3] = count['h' - 'a'] - nums[8]; // three - eight
nums[5] = count['f' - 'a'] - nums[4]; // five - four
nums[7] = count['s' - 'a'] - nums[6]; // seven - six
nums[1] = count['o' - 'a'] - nums[0] - nums[2] - nums[4]; // one - zero - two - four
nums[9] = count['i' - 'a'] - nums[5] - nums[6] - nums[8]; // nine - five - six - eight
// 构建结果字符串
string result;
for (int i = 0; i < 10; i++) {
result += string(nums[i], '0' + i);
}
return result;
}
};
执行结果
C# 实现
- 执行用时:84 ms
- 内存消耗:36.2 MB
Python 实现
- 执行用时:44 ms
- 内存消耗:15.1 MB
C++ 实现
- 执行用时:4 ms
- 内存消耗:6.8 MB
性能对比
| 语言 | 执行用时 | 内存消耗 | 特点 |
|---|---|---|---|
| C# | 84 ms | 36.2 MB | 代码结构清晰,但性能较差 |
| Python | 44 ms | 15.1 MB | 代码简洁,性能中等 |
| C++ | 4 ms | 6.8 MB | 性能最优,内存占用最小 |
代码亮点
- 🎯 利用字符唯一性巧妙解决重叠问题
- 💡 使用数组统计优化性能
- 🔍 按特定顺序处理避免干扰
- 🎨 代码结构清晰,注释完整
常见错误分析
- 🚫 忽略字符重叠情况
- 🚫 处理顺序错误导致统计错误
- 🚫 未考虑数字出现多次的情况
- 🚫 字符统计数组越界
解法对比
| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
|---|---|---|---|---|
| 字符统计法 | O(n) | O(1) | 实现简单,性能好 | 依赖字符唯一性 |
| 暴力匹配法 | O(n²) | O(n) | 思路直观 | 性能差 |
相关题目
- LeetCode 299. 猜数字游戏 - 中等
- LeetCode 451. 根据字符出现频率排序 - 中等
📖 系列导航
🔥 算法专题合集 - 查看完整合集
📢 关注合集更新:点击上方合集链接,关注获取最新题解!目前已更新第423题。
💬 互动交流
感谢大家耐心阅读到这里!希望这篇题解能够帮助你更好地理解和掌握这道算法题。
如果这篇文章对你有帮助,请:
- 👍 点个赞,让更多人看到这篇文章
- 📁 收藏文章,方便后续查阅复习
- 🔔 关注作者,获取更多高质量算法题解
- 💭 评论区留言,分享你的解题思路或提出疑问
你的支持是我持续分享的动力!
💡 一起进步:算法学习路上不孤单,欢迎一起交流学习!