13. Roman to Integer題目和答案詳解
1 題目簡述
Given aroman numeral, convert it to an integer.
Input isguaranteed to be within the range from 1 to 3999.
給定一個羅馬數字,將其轉換為整數。
輸入保證在1到3999的範圍內。
2 答案詳解(1) 規則分析
首先,要知道羅馬數字有7個:I(1),V(5),X(10),L(50),C(100),D(500),M(1000)。然後要知道羅馬計數的一些規則,先來看這樣的例子:阿拉伯數字1~11用羅馬數字表示為:
I、II、III、IV、V、VI、VII、VIII、IX、X、XI
以此為例,說明四點一般規則:
1)只有I、X、C可作為餘下數字的字首,例如VM、LC則為非法。
2)對於I、X、C(1開頭的數字,M除外)來說,單次使用量最多不能4個,這是因為IIII是非法的,IV才是正確合法的,還有XXXX是非法的,XL才是正確合法的。
3)對於V、L、D(5開頭的數字)來說,單次使用量最多為1個,這是因為VV不能表示10,而X才表示10。
4)此外,還有一些非法數字的情況,例如:XIIX,它符合前3點規則,將其分開為XI和IX,即為11和9,相加得20,但XX才表示20,故XIIX是非法的。同理,DCCCD也是非法的。ps:一個阿拉伯數字只有一種羅馬數字表示法。
注意:羅馬數字表示法還有一種規則是在數字上方加上橫線,表示其1000倍的數,但對於本次題目,上述四項規則已經足以解決。
(2)
解決思想
根據所述規則,由於採用C++來編寫程式,而C++相對於C語言特性中重要的一點是面向物件程式設計(OOP),故本次設計採用類的方法實現,該類表明所儲存的資料型別為vector<char>的容器。設計總體分兩步進行:
1)初步判斷輸入的羅馬數字是否合法。首先,若輸入的字母中含有7個羅馬數字之外的數字,則為非法;然後,若是違反了前三項規則,則為非法。依次將合法的數字放入容器中。在初步判斷正確的情況下,仍然無法避免會違反第四項規則。對於是否符合第四項規則的合法性,則留給將初步合法的數字轉化為阿拉伯數字時判斷。
2)從頭開始遍歷容器,從高位到低位,依次將每一項加入到結果中。對於有字首的項,有且只有一個字首數字(例如IV、IX),故I、X、C若是遇到比其大的數字則求其組合代表的阿拉伯數字值(例如求IV為4,IX為9);對於有後綴的項則不用將其組合,因為VIII為5+1+1+1的值;對於第四項規則的處理,可以看到加入到結果中的項是從高位加到低位的,所以若在累加的過程中,遇到前一個加入的項小於後一個加入的項時,則為非法(例如XIIX:9+1+10,1比10小,所以該數字非法),這是因為從高位到低位的項只可能越來越小;最後,對於保證羅馬數字的值在1~3999範圍,則由最後的結果判斷。
(3) 設計程式
所設計的程式採用類模板,雖然本次模板設計沒有體現其延伸性和程式碼重用性,但也是出於此目的所養成的習慣。程式如下:#include <iostream>
#include <vector>
#include <algorithm>
using std::cin;
using std::cerr;
using std::cout;
using std::endl;
using std::vector;
void display(char& c)
{
cout << c;
}
template<class T>
class RomanToInteger
{
private:
vector<T> romans_;
public:
RomanToInteger(const vector<T>& romans = vector<T>(0)):romans_(romans) {}
int result();
private:
void judge();
void exit_() {
cerr << "Wrong Input" << endl;
exit(EXIT_FAILURE);
}
void out_range() const {
cerr << "Out of Range" << endl;
exit(EXIT_FAILURE);
}
};
template<class T>
void RomanToInteger<T>::judge()
{
typename vector<T>::iterator it;
int count;
int left;
for(it = romans_.begin(); it != romans_.end(); it++) {
left = distance(it,romans_.end());
if(left == 0) {
exit_();
} else if(*it == 'C' or *it == 'X' or *it == 'I') {
if(left > 3 and *it == *(it + 1) and *it == *(it + 2) and *it == *(it + 3)) {
exit_();
} else if(left > 1 and *it == 'I' and (*(it + 1) == 'L' or *(it + 1) == 'C'
or *(it + 1) == 'D' or *(it + 1) == 'M')) {
exit_();
} else if(left > 1 and *it == 'X' and (*(it + 1) == 'D' or *(it + 1) == 'M')) {
exit_();
}
} else if(*it == 'D' or *it == 'L' or *it == 'V') {
if(left > 1 and *it == *(it + 1)) {
exit_();
} else if(left > 1 and *it == 'V' and (*(it + 1) == 'X' or *(it + 1) == 'L'
or *(it + 1) == 'C' or *(it + 1) == 'D' or *(it + 1) == 'M')) {
exit_();
} else if(left > 1 and *it == 'L' and (*(it + 1) == 'C' or *(it + 1) == 'D'
or *(it + 1) == 'M')) {
exit_();
} else if(left > 1 and *it == 'D'and *(it + 1) == 'M') {
exit_();
}
}
}
cout << "The Number is:";
for_each(romans_.begin(),romans_.end(),display);
cout << endl;
return;
}
template<class T>
int RomanToInteger<T>::result()
{
judge();
int res(0);
int add(0);
int add_before(0);
typename vector<T>::iterator it;
for(it = romans_.begin(); it != romans_.end(); it++) {
if(*it == 'I') {
if(*(it + 1) == 'X') {
add = 9;
it++;
} else if(*(it + 1) == 'V') {
add = 4;
it++;
} else {
add = 1;
}
} else if(*it == 'V') {
add = 5;
} else if(*it == 'X') {
if(*(it + 1) == 'C') {
add = 90;
it++;
} else if(*(it + 1) == 'L') {
add = 40;
it++;
} else {
add = 10;
}
} else if(*it == 'L') {
add = 50;
} else if(*it == 'C') {
if(*(it + 1) == 'M') {
add = 900;
it++;
} else if(*(it + 1) == 'M') {
add = 400;
it++;
} else {
add = 100;
}
} else if(*it == 'D') {
add = 500;
} else if(*it == 'M') {
add = 1000;
}
if(!add_before) {
add_before = add;
} else if(add_before < add) {
exit_();
} else {
add_before = add;
}
res += add;
if(res > 3999) {
out_range();
}
}
if(res == 0) {
out_range();
}
return res;
}
int main()
{
vector<char> vec;
char ch;
int res;
cout << "Please Iuput Number of Roman:";
while((ch = cin.get()) != '\n') {
if(ch != 'M'and ch != 'D'and ch != 'C'and ch != 'L'and ch != 'X'and ch != 'V' and ch != 'I') {
cerr << "Wrong Input" << endl;
exit(EXIT_FAILURE);
} else {
vec.push_back(ch);
}
}
RomanToInteger<char> rti(vec);
res = rti.result();
cout << "Integer Number:" << res << endl;
}
本次測試了4種不同輸入情況的執行結果,執行結果為:
Please Iuput Number of Roman:ASDCF
Wrong Input
Please Iuput Number of Roman:VX
Wrong Input
Please
Iuput Number of Roman:XIIX
The Number is:XIIX
Wrong Input
Please
Iuput Number of Roman:MDCLXVI
The Number is:MDCLXVI
Integer Number:1666