本篇博客会讲解力扣中“13. 罗马数字转整数”这道题的解题思路。
大家先来审下题:题目链接。
题干如下:
有几个输出样例:
提示如下:
大家先思考一下,再来听我讲解。
本题的关键是:如何把罗马数字转换成整数?其实,题目中给的“罗马数字”本质上是一个字符串,这道题应该归类于字符串系列。字符串常规的遍历思路,大家一定要掌握。
既然是一个字符串,一定是要遍历的,大家可以使用while循环,这么写:
char* cp = s;
while (*cp)
{
// ...
++cp;
}
或者使用for循环,这么写:
for (char* cp = s; *cp; ++cp)
{
// ...
}
我更加喜欢使用for循环,因为当中间的操作太长的时候,容易忘记++cp的迭代操作,而且读起来让我有种“不爽”的感觉。不过这不是重点,大家挑选自己喜欢的写法就行了。
当遍历到其中一个字符时,我们就可以根据“转换表”,转换成对应的数字了。大家可以使用switch case,或者写一堆if else,但是我更建议先把“转换规则”存到一个数组中,转换时直接到数组中找就行了。
这个数组应该如何实现呢?思路可以类似哈希表:下标代表要转换的罗马字符,数组存储的数据代表该罗马字符对应的数字。由于罗马字符都是大写字母,数组只需要26个元素就能够涵盖所有情况了。
再详细一点:罗马字符对应到数字的规则是:先把罗马字符对应的大写字母转换成下标,规则是pos=罗马字符-'A';
再通过下标找到罗马字符对应的数字,即values[pos]
。写成代码如下:
int romanToInt(char * s){
// 使用数组存储罗马字符对应的数字
static int values[26] = {0};
values['I'-'A'] = 1;
values['V'-'A'] = 5;
values['X'-'A'] = 10;
values['L'-'A'] = 50;
values['C'-'A'] = 100;
values['D'-'A'] = 500;
values['M'-'A'] = 1000;
// 遍历字符串
for (char* cp = s; *cp; ++cp)
{
// ...
}
}
接下来,只需要把遍历到的罗马字符转换成对应的数字即可。这里需要科普以下转换规则。详细的规则题干中有说明,这里我简化一下:对于一个罗马数字,如果左大右小(大多数情况),规则是“相加”;如果左小右大,规则是“相减”。
所以,我们不仅需要遍历当前字符,还需要看该字符右边的字符,比较它们对应的数字的大小关系,来确定是“加上”还是“减去”该字符。这里需要注意:如果当前字符右边就是’\0’,就假设右边的字符对应的数字是0就行了,因为罗马字符对应的数字一定大于0,所以会归类于“左大右小”,此时的效果是“相加”,符合逻辑。
代码实现如下:
int romanToInt(char * s){
// 使用数组存储罗马字符对应的数字
static int values[26] = {0};
values['I'-'A'] = 1;
values['V'-'A'] = 5;
values['X'-'A'] = 10;
values['L'-'A'] = 50;
values['C'-'A'] = 100;
values['D'-'A'] = 500;
values['M'-'A'] = 1000;
// 遍历字符串
int ret = 0;
for (char* cp = s; *cp; ++cp)
{
// 计算该字符对应的数字
int left = values[*cp-'A'];
// 计算该字符右边的字符对应的数字
int right = 0;
if (*(cp+1))
right = values[*(cp+1)-'A'];
// 判断左右大小关系
if (left >= right)
ret += left;
else
ret -= left;
}
return ret;
}
这就通过了。是不是很简单?
总结
- 字符串的遍历一定要掌握。
- 运用到了类似哈希表的思路,把数据先存储到数组中,需要的时候去数组中找就行了。
感谢大家的阅读!