题目:
Given a roman numeral, convert it to an integer.
Input is guaranteed to be within the range from 1 to 3999.
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。。。