LeetCodeで解いたからというのもありますが、ローマ数字を10進数に変換する方法を簡単に紹介します。
目次
ローマ数字の読み方
これを読んでいるということは、まずローマ数字と仲良くなる必要があるかもしれません。が、ここでは割愛します。仲良くなっている前提で進めます。
左から順に計算する方法
まずパッと思い浮かんだ方法がこれでした。本当は右から読むのが正解なのかもしれませんが……
下記がその実装です。
class Solution {
public:
int romanToInt(string s) {
static const std::unordered_map<char, unsigned short> char_to_value {
{ 'I', 1 },
{ 'V', 5 },
{ 'L', 50 },
{ 'X', 10 },
{ 'C', 100 },
{ 'D', 500 },
{ 'M', 1000 }
};
int return_value = 0;
int same_roman_sum = 0;
const size_t size = s.size();
for (size_t i = 0; true; i++) {
const unsigned short current_digit = char_to_value.at(s[i]);
if (i == size - 1) {
return_value += current_digit + same_roman_sum;
break;
}
const unsigned short right_digit = char_to_value.at(s[i + 1]);
if (current_digit > right_digit) {
return_value += current_digit + same_roman_sum;
same_roman_sum = 0;
} else if (current_digit < right_digit) {
return_value -= current_digit + same_roman_sum;
same_roman_sum = 0;
} else {
same_roman_sum += current_digit;
}
}
return return_value;
}
};
やっていることはこんな感じです。
- 左から順に、今見ている桁と右の桁を比較
- 右の桁より大きければそのまま足す
- 右の桁より小さければ負数を足す
- 右の桁と同じだったら覚えておく
- 最後の桁は足す
左の桁から順に読む方法
こっちの方がシンプルに書けるので好みです。
ちなみに、実行時間やメモリ効率はほぼ同じでした。
class Solution {
public:
int romanToInt(string s) {
static const std::unordered_map<char, unsigned short> char_to_value {
{ 'I', 1 },
{ 'V', 5 },
{ 'L', 50 },
{ 'X', 10 },
{ 'C', 100 },
{ 'D', 500 },
{ 'M', 1000 }
};
int return_value = 0;
int right_digit = 0;
for (int i = s.size() - 1; 0 <= i; i--) {
const int current_digit = char_to_value.at(s[i]);
if (current_digit >= right_digit) {
return_value += current_digit;
right_digit = current_digit;
} else {
return_value -= current_digit;
}
}
return return_value;
}
};
やっていることはこんな感じです。
- 右のから順に、右の桁と比較
- 右の桁以上ならそのまま足す&次回の右の桁として覚える
- 右の桁より小さい場合は負数を足す
以上です!