LeetCode Algorithm #13 Roman to Integer
题目内容
Given a roman numeral, convert it to an integer.
Input is guaranteed to be within the range from 1 to 3999.
解题
首先要理解罗马数字组成的规则,百度百科是这样写的。
- 相同的数字连写、所表示的数等于这些数字相加得到的数、如:Ⅲ=3;
- 小的数字在大的数字的右边,所表示的数等于这些数字相加得到的数,如:Ⅷ=8、Ⅻ=12;
- 小的数字(限于 I、X 和 C)在大的数字的左边,所表示的数等于大数减小数得到的数,如:Ⅳ=4、Ⅸ=9;
- 正常使用时,连写的数字重复不得超过三次;
- 在一个数的上面画一条横线,表示这个数扩大 1000 倍。
但我觉得这些规则仍然不能很好的确定一个罗马数字,应该再加上如下规则。
- 放在大的数字左边表示减去的小数字只能使用一种符号,比如不能使用CIM来表示901。
- 各个数字严格遵循从左向右减小,比如1900要使用MCM来表示,而不能使用CMM。
于是这样我们可以把每个数位分开:千位数上为M、MM、MMM;百位数上为C、CC、CCC、CD、D、DC、DCC、DCCC、CM;十位数上为X、XX、XXX、LX、L、LX、LXX、LXXX、XC;个位数上为I、II、III、IV、V、VI、VII、VIII、IX。
这样我们就可以使用逐位匹配来将罗马数字转换为整型,使用空字符串来表示该位上为0,所以要从大向小匹配。
class Solution {
public:
int romanToInt(string s) {
string c[4][10] = {
{"","I","II","III","IV","V","VI","VII","VIII","IX"},
{"","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"},
{"","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"},
{"","M","MM","MMM"}
};
int result = 0, top = 3, offset = 0, length;
string temp;
for(int i = 3; i >= 0; --i) {
for(int j = top; j >= 0; --j) {
temp = c[i][j];
length = temp.length();
if(s.substr(offset, length) == temp) {
result = result*10 + j;
offset += length;
break;
}
}
top = 9;
}
return result;
}
};
暂时还没有想好优化,运行时间也是玄学的一逼,第一次提交是最快的,35ms,今天提交了几次都在80-90。