前言
额想了个把小时都没有很好的主意去处理六个特殊情况。
参考
正文
提示:
- 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,只管累加就行。。。确实优秀