
Day 6。
今天这两题是一组非常经典的“配套题”:
12. Integer to Roman13. Roman to Integer
一道是 整数转罗马数字,一道是 罗马数字转整数。
这种前后对应的题特别适合加深理解,因为你不仅要会“写出去”,还要会“读回来”。
今天的关键词:贪心、模拟、映射、特殊规则处理。
🧠 LeetCode 12 – Integer to Roman
💡 思路总结
这题的核心其实很直接:
每次优先减去当前能匹配的最大罗马数字值
比如 1994:
- 先减
1000,得到M - 再减
900,得到CM - 再减
90,得到XC - 再减
4,得到IV
最后拼起来就是:
MCMXCIV
这就是一个很典型的 贪心思想。
💻 代码实现
class Solution {
public:
string intToRoman(int num) {
vector<int> values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
vector<string> symbols = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
string result;
int num_ = num;
while(num_ != 0){
for(int i = 0 ; i<values.size();i++){
if (num_ >= values[i]){
num_ = num_-values[i];
result += symbols[i];
break;
}
}
}
return result;
}
};
📌 知识点总结
1️⃣ 贪心思想
这题很适合理解贪心:
- 当前能选最大的,就先选最大的
- 每次都尽快让剩余值减少
因为罗马数字的规则本身就是固定组合,所以这种贪心是成立的。
2️⃣ 特殊值要提前放进去
你这里把这些值都提前放进数组里了:
900 -> CM
400 -> CD
90 -> XC
40 -> XL
9 -> IX
4 -> IV
这一步非常关键。
因为罗马数字不是单纯地一直拼 I、X、C,它有减法表示法。
比如:
4不是IIII9不是VIIII
而是:
IVIX
所以这些特殊组合必须直接参与匹配。
3️⃣ 数据与规则绑定
这里用两个数组:
valuessymbols
本质是在做“值和表示法的映射”。
这种写法很常见,尤其适合规则固定、顺序明确的模拟题。
🏛️ LeetCode 13 – Roman to Integer
💡 思路总结
这一题反过来,要把罗马数字转成整数。
你的思路是:
先判断两个字符能不能匹配特殊组合,再判断单个字符
这个想法是对的,而且非常关键。
因为像:
IVIXXLXCCDCM
这些必须优先作为整体识别。
不然你如果先按单字符处理,IV 就会被拆成:
I = 1V = 5
结果变成 6,显然错了。
💻 代码实现
class Solution {
public:
int romanToInt(string s) {
vector<int> values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
vector<string> symbols = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
int result = 0;
//应该先判断两个,在判断一个
for(int i = 0 ; i < s.size(); i ++){
bool match = false;
string new_ = s.substr(i,2);
for(int j = 0 ;j < symbols.size(); j ++){
if(new_ ==symbols[j]){
result += values[j];
i++;
match = true;
break;
}
}
if(!match){
string new_ = s.substr(i,1);
for (int k = 0;k<symbols.size();k++){
if(new_ ==symbols[k]){
result += values[k];
match = true;
break;
}
}
}
}
return result;
}
};
📌 知识点总结
1️⃣ 优先匹配长的
这是这题的灵魂:
先看两个字符,再看一个字符
因为双字符组合优先级更高。
这个思路在字符串题里也很常见:
当存在“长匹配”和“短匹配”冲突时,往往要优先处理更长的那个。
2️⃣ substr 的使用
你这里用了:
s.substr(i, 2)
s.substr(i, 1)
这个写法很直观,逻辑也清晰。
对当前阶段来说,非常适合做题和理解。
3️⃣ 模拟题的本质
这题本质还是一题规则模拟:
- 按顺序扫描字符串
- 判断当前应该匹配哪种模式
- 匹配成功就更新结果和下标
所以这类题最重要的不是“玄学技巧”,而是你能不能把规则拆清楚。
🧩 两题放在一起看
今天这两题特别适合放在一起理解:
| 题目 | 核心思想 |
|---|---|
| LeetCode 12 | 贪心 + 枚举最大匹配值 |
| LeetCode 13 | 模拟 + 优先匹配双字符 |
它们本质上都在做同一件事:
用固定规则表,完成数值和字符串之间的转换
🧠 今日收获
今天可以重点记住这两个模型。
1. 固定规则转换题
如果题目规则是固定且有限的,可以考虑:
- 建表
- 按顺序匹配
- 映射转换
这类写法非常稳。
2. 特殊情况前置
很多题的难点不是主体逻辑,而是特殊规则:
- 罗马数字里的减法表示
- 双字符优先匹配
- 不能只按单个字符贪算
这提醒我们一件事:
写题时要先想“有没有特殊规则”,再写主逻辑。
✍️ 一个可以继续优化的小点
你这两题都已经能过,而且思路也很正。
不过博客里可以顺带记一下一个提升点:
LeetCode 12
你现在是每次都从头扫一遍 values,没问题,但写法可以再简洁一点,比如:
for (int i = 0; i < values.size(); i++) {
while (num >= values[i]) {
num -= values[i];
result += symbols[i];
}
}
这样结构会更紧凑。
LeetCode 13
你现在是用双层循环查找匹配,也能做。
后面如果你想优化,可以考虑哈希表或字符值映射,让查找更快、代码更短。
但在当前阶段,先把规则理解透,比盲目追求最短代码更重要。
💬 写给自己的话
Day 6 了。
已经不是“试着刷一刷”的阶段了,
你现在是真的在持续积累。
今天这种成对出现的题很有价值,
因为你不只是做了一题,而是在练:
- 正向转换怎么想
- 逆向转换怎么处理
- 规则题怎么拆
- 特殊情况怎么优先判断
这比单纯 AC 更重要。
继续保持这个节奏。
一天天看起来很普通,
但题感、代码能力、边界意识,都是这样一点点堆起来的。
别小看每天这两题。
你现在写下的每一篇总结,都会在后面某一天变成你的底气。
阿玉,Day 6,继续冲。
—— 刷题第 6 天
