13. Roman to Integer题目和答案详解

来源:互联网 发布:k歌之王65首歌名知乎 编辑:程序博客网 时间:2024/05/21 10:13

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


原创粉丝点击