【问题标题】:c++ Converting roman numerals to decimalsc ++将罗马数字转换为小数
【发布时间】:2020-08-30 09:04:57
【问题描述】:

这个程序是我刚参加的考试的一部分,我必须写。我只到了这么远,什么地方都没有。提示如下:“编写一个测试函数 toDecimal(),将 MMLXVII 等罗马数字转换为其十进制数表示。使用 Main() 测试函数。toDecimal() 函数应该有 2 个参数,字符串数组罗马数字和一个辅助函数。这个辅助函数将返回罗马数字中使用的每个字母的数值。然后将字符串参数转换为:查看前两个字符,如果第一个较大,则转换第一个和将其添加到总和中,然后使用第二个值再次调用转换函数并将两者相加。如果第一个字符小于第二个字符,则从第二个字符中减去第一个字符,并将结果添加到字符串的转换中。未经验证还将转换字符串,如“IC”。验证字符串参数,如果有错误,调用错误处理函数。提供至少两个错误处理函数,并分别测试 toDecimal()。一个可能是建议用户使用 cor rect,对方可以更正。”

I,X,C,M不能连续重复超过3次,D,L,V,不能连续重复。I只能从V中减去,X,X只能从L中减去和C,C只能从D和M中减去。V,L和D永远不能减去。

我为此失去了大约 2 天的睡眠时间,尝试使用和违反规则的数百种不同方式编写它。这是我最接近的。

#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <cstring>
using namespace std;

bool checker(string roman);
// Adds each value of the roman numeral together
int toDecimal(string, bool* (*function)(string));
int convert(string roman, int i);

int main(){
    string roman;
    cout << "This program takes a roman numeral the user enters then converts it to decimal notation." << endl;
    cout << "Enter a roman numeral: ";
    cin >> roman;
    transform(roman.begin(), roman.end(), roman.begin(), toupper);
    cout << roman << " is equal to " << toDecimal(roman,  *checker(roman)) << endl;
}

bool checker(string roman){
    int length = roman.length();
    for (int count = 0; count < length; count++){
        string sub = roman.substr(count, count);
        if(sub != "I" || sub != "V" || sub != "X" || sub != "L" || sub != "C" || sub != "D" || sub != "M"){
            cout << "Error. Try Again"<< endl;
            return false;
        }
        else if(convert(roman, count) == convert(roman, count-1) && convert(roman, count) == convert(roman, count+1)){
            if (convert(roman,count) == 1 || convert(roman,count) == 10 || convert(roman,count) == 100 || convert(roman,count) == 1000)
                if(convert(roman, count-1) == convert(roman, count-2) || convert(roman, count+1) == convert(roman, count+2)){
                    cout << "Error Try again" << endl;
                    return false;
                }
            else if (convert(roman,count) == 5 || convert(roman,count) == 50 || convert(roman,count) == 500){
                cout << "Error Try again" << endl;
                    return false;
            }
            else return true;

        }           
    }
    return true;
}

int toDecimal(string s, bool*(checker) (string roman)){
    /**map<char, int> roman;
    roman['M'] = 1000;
    roman['D'] = 500;
    roman['C'] = 100;
    roman['L'] = 50;
    roman['X'] = 10;
    roman['V'] = 5;
    roman['I'] = 1;*/
    checker(s);
    int res = 0;
    for (int i = 0; i < s.length() - 1; ++i){
        int num = convert(s,i);
        res += num;
        /**if (roman[s[i]] < roman[s[i+1]])
            res -= roman[s[i]];
        else
            res += roman[s[i]];
    }
    res += roman[s[s.size()-1]];*/}
    return res;
}

int convert(string roman, int i){
    enum romans {I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000};
    int num = 0;
    char c = roman[0]; 
    switch(c){
        case 'M': 
            num = M; break;
        case 'D':   
            if(i + 1 != roman.size() && roman[i+1] == 'M'){
                num = M - D;break;
            }
            else
                num = D; break;
        case 'C': 
            if(i + 1 != roman.size() && roman[i+1] == 'M' || roman[i+1] == 'D'){
                if(roman[i+1] == 'M') num = M - C; break;
                if(roman[i+1] == 'D') num = D - C; break;
            }
            else
                num = C; break;
        case 'L':
            if(i + 1 != roman.size() && roman[i+1] == 'M' || roman[i+1] == 'D' || roman[i+1] == 'C'){
                if(roman[i+1] == 'M') num = M - L; break;
                if(roman[i+1] == 'D') num = D - L; break;
                if(roman[i+1] == 'C') num = C - L; break;
                }
            else
                num = L; break;
        case 'X': 
            if(i + 1 != roman.size() && roman[i+1] == 'M' || roman[i+1] == 'D' || roman[i+1] == 'C'|| roman[i+1] == 'L'){
                if(roman[i+1] == 'M') num = M - X; break;
                if(roman[i+1] == 'D') num = D - X; break;
                if(roman[i+1] == 'C') num = C - X; break;
                if(roman[i+1] == 'L') num = C - X; break;
            }
                num = X; break;
        case 'V':
            if(i + 1 != roman.size() && roman[i+1] == 'M' || roman[i+1] == 'D' || roman[i+1] == 'C'|| roman[i+1] == 'L' || roman[i+1] == 'X'){
                if(roman[i+1] == 'M') num = M - V; break;
                if(roman[i+1] == 'D') num = D - V; break;
                if(roman[i+1] == 'C') num = C - V; break;
                if(roman[i+1] == 'L') num = L - V; break;
                if(roman[i+1] == 'X') num = X - V; break;
            }
                num = V; break;
        case 'I':
            if ( i + 1 != roman.size() && roman[i + 1] != 'I'){
                if(roman[i+1] == 'M') num = M - I; break;
                if(roman[i+1] == 'D') num = D - I; break;
                if(roman[i+1] == 'C') num = C - I; break;
                if(roman[i+1] == 'L') num = L - I; break;
                if(roman[i+1] == 'X') num = X - I; break;
            }
                num =1; break;
    }
    return num;
}

** 我在这里添加了人们的帮助。这是显示进度/大会的编辑。

【问题讨论】:

  • 您在各个地方定义 enum 值,然后不使用它们 - 这真的没有用。
  • 很多东西都行不通。我真的迷失了。我最初为注释掉的内容制作了罗马枚举,另一个枚举是为了让我可以尝试比较“sub”,因为我不能
  • @user2592862 首先,您的 ToDecimal 函数没有正确的签名。应该是int ToDecimal( std::string const&amp; input, int (*convert)( char ch ) )(至少根据你给出的描述)。
  • +1 为您的辛勤工作。我阅读了您的问题陈述,但我不知道您实际需要什么。所以我只是将converting roman to integer 的解决方案放在答案中。

标签: c++ visual-c++


【解决方案1】:

这是我用来将 Roman(小于 3999)转换为 Integer 的代码。您可以检查它是否适用于更大的数字。

int romanToInt(string s) {
    map<char, int> roman;
    roman['M'] = 1000;
    roman['D'] = 500;
    roman['C'] = 100;
    roman['L'] = 50;
    roman['X'] = 10;
    roman['V'] = 5;
    roman['I'] = 1;

    int res = 0;
    for (int i = 0; i < s.size() - 1; ++i)
    {
        if (roman[s[i]] < roman[s[i+1]])
            res -= roman[s[i]];
        else
            res += roman[s[i]];
    }
    res += roman[s[s.size()-1]];
    return res;
}

希望对你有帮助。

【讨论】:

  • 你好,我一直在寻找这样的东西,因为我渴望学习 STL。我想知道如何进行相反的操作,字符串 roman(int num) 所以它返回整数的罗马形式。这很容易逆转吗,只是简单地逆转迹象吗?我迷失在地图和双重潜艇上......
  • @JonWeinraub 希望这个链接可以帮助你。 github.com/AnnieKim/LeetCode/blob/master/IntegertoRoman.h
【解决方案2】:

Annie Kim 提供的解决方案有效,但它使用 std::map,多次查询同一个字符,但我找不到原因。

int convert_roman_digit(char d)
{
    switch (d)
    {
        case 'M': return 1000;
        case 'D': return 500;
        case 'C': return 100;
        case 'L': return 50;
        case 'X': return 10;
        case 'V': return 5;
        case 'I': return 1;
        default: throw std::invalid_argument("Invalid digit");
    }
}

int roman_to_int(const std::string& roman)
{
    int result = 0, last_added = 0;

    for (auto it = roman.rbegin(); it != roman.rend(); ++it)
    {
        const int value = convert_roman_digit(*it);
        if (value >= last_added)
        {
            result += value;
            last_added = value;
        }
        else
        {
            result -= value;
        }
    }

    return result;
}

警告:该函数很乐意接受一些无效输入(例如IMM),包括“负”数字(例如IIIIIIIIIIIIIX),没有溢出检查,它会抛出。随意改进它。

【讨论】:

    【解决方案3】:
    int romanToInt(string s)
    {
        unordered_map<char, int> roman;
        roman['I'] = 1;
        roman['V'] = 5;
        roman['X'] = 10;
        roman['L'] = 50;
        roman['C'] = 100;
        roman['D'] = 500;
        roman['M'] = 1000;
    
        int num = 0, prev = 0, curr;
        for (int i = s.length() - 1; i >= 0; i--)
        {
            curr = roman[s[i]];
            num += (curr >= prev ? 1 : -1) * curr;
            prev = curr;
        }
        return num;
    }
    

    【讨论】:

    • 仅代码的答案不被视为有用的答案。请添加评论为什么您的代码比早期答案中的代码更好。
    猜你喜欢
    • 2019-01-09
    • 2011-10-25
    • 1970-01-01
    • 1970-01-01
    • 2012-10-27
    • 2014-03-04
    • 2012-10-09
    相关资源
    最近更新 更多