前言

额想了个把小时都没有很好的主意去处理六个特殊情况。


参考

  • switch
  • string

正文

提示:

  • 1 <= s.length <= 15
  • s 仅含字符 (‘I’, ‘V’, ‘X’, ‘L’, ‘C’, ‘D’, ‘M’)
  • 题目数据保证 s 是一个有效的罗马数字,且表示整数在范围 [1, 3999] 内
  • 题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。
  • IL 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。

好处是罗马数字就七种字符,坏处有特殊的组合
且字符串s长度不超过15,转换后的整数范围不超过3999,这样倒是不用担心越界了。

初始代码:

1
2
3
4
5
6
class Solution {
public:
int romanToInt(string s) {

}
};

最后返回转换的罗马数字即可。


初解

因为就7个字符,感觉可以用switch直接套,不然用map再套一层好像增加空间了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int romanToInt(string s) {

}

int getCsetV(char c){
switch(c){
case 'I' : return 1; break;
case 'V' : return 5; break;
case 'X' : return 10; break;
case 'L' : return 50; break;
case 'C' : return 100; break;
case 'D' : return 500; break;
case 'M' : return 1000; break;
default: return 0; break;
}
}
};

就先封装一个函数,但是问题就在于那几个特殊组合的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public:
int romanToInt(string s) {
int n = 0;

for(int i = 0; i < s.length(); i++){
if(s[i] < s[i+1]){
n += getCsetV(s[i+1]) - getCsetV(s[i]);
}else{
n += getCsetV(s[i]);
}
}
}

int getCsetV(char c){
switch(c){
case 'I' : return 1; break;
case 'V' : return 5; break;
case 'X' : return 10; break;
case 'L' : return 50; break;
case 'C' : return 100; break;
case 'D' : return 500; break;
case 'M' : return 1000; break;
default: return 0; break;
}
}
};

遍历一遍是肯定要的,但是如果判断的是字符相不相等,再使其控制n += 的情况,又有点不对头,因为i到了字符串末尾的时候,i+1就越界了不说。。单纯的s[i]返回的是字符,也不能作为比较的条件,那么就要创建两个变量或者是if的时候就要把s[i]放到getCsetV里面。

1
2
3
4
5
6
7
for(int i = 0; i < s.length(); i++){
if(getCsetV(s[i]) < getCsetV(s[i+1])){
n += getCsetV(s[i+1]) - getCsetV(s[i]);
}else{
n += getCsetV(s[i]);
}
}

这样修改后,测试的时候就会发现问题了,比如”IV”:

貌似多了个5。。其实原因就是i<的是s.length();
两个字符的时候,0 和 0+1已经判断过了,就没必要让i在自增了,解决办法就是i < s.length()-1;

-1方法不可取,之前脑子又陷进去了,为什么这么说呢,因为IV是特殊组合,它不需要像正常那样从左+到右,它是一组固定的值,如果我-1了,那个字符串正好是”LVIII“的话,最后的i就被舍弃了。

debug了一圈,抓到是n+的问题。如果后者大于前者,n+=后者-前者,但是最后还是要额外+一个后者。
所以应该是后者大于前者时,n -= 前者,n此时为负数,然后就是正常情况下n += 后者。

1
2
3
4
5
if(getCsetV(s[i]) < getCsetV(s[i+1])){
n -= getCsetV(s[i]);
}else{
n += getCsetV(s[i]);
}

最后又测了几个示例,应该是差不多了,提交一下:

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
int romanToInt(string s) {
int n = 0;

for(int i = 0; i < s.length(); i++){
if(getCsetV(s[i]) < getCsetV(s[i+1])){
n -= getCsetV(s[i]);
}else{
n += getCsetV(s[i]);
}
}

return n;
}

int getCsetV(char c){
switch(c){
case 'I' : return 1; break;
case 'V' : return 5; break;
case 'X' : return 10; break;
case 'L' : return 50; break;
case 'C' : return 100; break;
case 'D' : return 500; break;
case 'M' : return 1000; break;
default: return 0; break;
}
}
};

优化

好像没有特别能优化的地方,唯一想优化的就是对那几组特殊组合,能有什么办法不用循环判断就好了,直接循环累加。
map在我的想法里用起来也挺麻烦的感觉。


结语

然后就是翻阅评论了,精选第一条其实就是解释了一个思想。

不过他用的hashmap,我是想如果能不额外增加变量那最好,虽然不知道hashmap的效率会不会更高。

然后就是一个秀儿的代码:

雀食有点意思啊,直接把字符串s替换一下,把那六个组合替换成别的代替的字符,然后switch的时候分别对应六个值,这样for循环雀食省了if,只管累加就行。。。确实优秀