LeetCode之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.

题目大意:

  给定一个罗马数字,将其转化为一个整数。转化好的整数的范围在1---3999之间。

思路:

  有了上一题的经验,我们可以将待转化的罗马数字和阿拉伯数字的映射创建一个表(这次只创建不同的符号和相减的组合情况,如:IX),然后从字符串的最后一个到第一个开始遍历,遍历一个加一个对应的阿拉伯数字,然后再和前边遍历的合在一起查找是否在表中,如果在则减掉多加的数字。

代码:

class Solution {
public:
    int romanToInt(std::string s) {
        int result = 0;
        int pos = s.size() - 1;
        //建表
        std::map<std::string, int> romanNums = {
            {"I", 1}, {"V", 5} , {"IV", 4}, {"IX", 9}, {"X", 10}, 
            {"L", 50}, {"XL", 40}, {"XC", 90}, {"XC", 90}, {"C", 100}, 
            {"CD", 400}, {"D", 500}, {"CM", 900}, {"M", 1000}
        };
        
        if (pos < 0) {
            return 0;
        }
        auto pre = romanNums.find(s.substr(pos, 1));
        std::map<std::string, int>::iterator tmp;
        while (pos >= 0) {
            auto now = romanNums.find(s.substr(pos, 1)); //查找对应的数字
            result += now->second;  //加到结果上
            if ((tmp = romanNums.find(now->first + pre->first)) != romanNums.end()) { //和前一个遍历的合起来是不是一个组合
                result = result - (now->second + pre->second - tmp->second);    //如果是组合,则删除多加的
            }
            pre = now; 
            --pos;
        }
        return result;
    }
};
  提交后发现发现好耗时啊(100ms左右)。。。。

优化:

  将上边思想进行优化,可以发现上边的思想在有组合出现时会出现先加再减的重复过程。所以可以在这里想办法把重复的这个过程减掉。其实不难发现出现组合情况的就是前一个小于后一个数,所以可以将上述思想反其道行之,从前向后扫描,当i的值小于i+1的值时将i的值减掉,否则将i的值加上。

优化后代码:

class Solution {
public:
    int romanToInt(std::string s) {
        int result = 0;
        if (s.empty()) {
            return 0;
        }
        std::map<char, int> romanNums = {
            {'I', 1}, {'V', 5}, {'X', 10}, {'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000}
        };
        
        for (int i = 0; i < s.size(); ++i) {
            if (i + 1 < s.size()) {
                if (romanNums.find(s[i])->second < romanNums.find(s[i + 1])->second) {
                    result -= romanNums.find(s[i])->second;
                } else {
                    result += romanNums.find(s[i])->second;
                }
            } else {
                result += romanNums.find(s[i])->second;
            }
        }
        
        return result;
    }
};

  运行时间60ms左右。根据上一道题的经验,将map换成int romanNums[89](因为'X'的ASCII码为88)应该可以减少时间。So。。。下边代码就诞生了。

class Solution {
public:
    int romanToInt(std::string s) {
        int result = 0;
        if (s.empty()) {
            return 0;
        }
        
        int romanNums[89];
        romanNums['I'] = 1;    romanNums['V'] = 5;    romanNums['X'] = 10;
        romanNums['L'] = 50;   romanNums['C'] = 100;  romanNums['D'] = 500;
        romanNums['M'] = 1000;
        
        for (int i = 0; i < s.size(); ++i) {
            if (i + 1 < s.size()) {
                if (romanNums[s[i]] < romanNums[s[i + 1]]) {
                    result -= romanNums[s[i]];
                } else {
                    result += romanNums[s[i]];
                }
            } else {
                result += romanNums[s[i]];
            }
        }
        
        return result;
    }
};

  最终时间36ms,可是这样的写法总感觉有点像C with class。。。

posted @ 2016-04-09 19:42  Jung_zhang  阅读(107)  评论(0编辑  收藏  举报