LeetCode Algorithm #13 Roman to Integer

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。

点赞