ฟังก์ชันตัวแปลงตัวเลขโรมัน


14

สร้างฟังก์ชั่นที่สั้นที่สุดเพื่อแปลงสตริงของตัวเลขโรมันให้เป็นจำนวนเต็ม

กฎสำหรับตัวอักษรแต่ละตัวสามารถพบได้ที่หน้าวิกิพีเดีย ตัวอักษรที่สูงกว่า 1,000 จะมีเครื่องหมายวงเล็บล้อมรอบพวกเขาเพื่อให้สัญญาณที่สูงกว่า

ที่ต้องการ:

  • ต้องแปลงตัวเลขโรมัน 1 ถึง 500,000
  • ต้องเสร็จในเวลาไม่ถึงนาที
  • ไม่ใช้ฟังก์ชันในตัวที่สามารถให้ประโยชน์ (เช่น: ฟังก์ชันที่แปลงตัวเลขโรมันเป็นจำนวนเต็ม)
  • เป็นฟังก์ชั่น

ฟังก์ชันไม่จำเป็นต้องรองรับเศษส่วน อินพุตที่ไม่ถูกต้องควรส่งคืนหมายเลข 0

ฟังก์ชั่นที่สั้นที่สุดชนะ ในกรณีที่เสมอกันผู้ที่มีคะแนนมากที่สุดชนะ

กรณีทดสอบ

อินพุต

III

เอาท์พุต

3


อินพุต

IIII

เอาท์พุต

0


อินพุต

XVI

เอาท์พุต

16


อินพุต

(C)(D)(L)MMI

เอาท์พุต

452001

2
ถ้าฉันไม่มีอะไร(C)(D)(L)MMIจะเป็น 452,001 คุณได้รับคุณค่าของคุณอย่างไร? นอกจากนี้สิ่งนี้จำเป็นต้องสนับสนุนฟอร์ม "ไม่เหมาะสม" (เช่นICแทนXCIX) หรือไม่
อานนท์

ไม่เหมาะสมสำหรับฉันหมายถึงสิ่งผิดกฎหมายดังนั้นควรคืน 0
Martin York

@Anon: หมายเลขเป็น mistype จากเมื่อฉันเปลี่ยนกรณีทดสอบที่สามเดิม ไม่จำเป็นต้องสนับสนุนรูปแบบที่ไม่เหมาะสมเพราะจะถือว่าเป็นการป้อนข้อมูลที่ไม่ถูกต้อง
เควินบราวน์

1
การปฏิบัติมาตรฐาน (และข้อมูลจำเพาะของคำถามนี้ซ้ำกัน) มีไว้สำหรับการป้อนข้อมูลที่ไม่ถูกต้องที่จะไม่ได้กำหนดพฤติกรรม เนื่องจากคำถามนี้มีอายุสี่ขวบและมีคำตอบเดียวเราควรเปลี่ยนข้อกำหนดหรือไม่
lirtosiast

1
@KevinBrown ฉันไม่เห็นแหล่งที่มาหรือคำอธิบายสำหรับตัวอักษรที่วงเล็บ ฉันคิดว่าคุณควรเปลี่ยนข้อมูลจำเพาะเพื่อให้ตรงกับcodegolf.stackexchange.com/q/16254/43319จากนั้นคำตอบจากที่นั่นสามารถโยกย้ายได้ที่นี่
Adám

คำตอบ:


6

C ++: 914 855 ตัวอักษร

#include<map>
#include<string>
#include<iostream>
#include<sstream>
#define I istream
#define T(C) if(C)throw int(1);
#define X(c,v,f,m) D[c]=v;P[c]=D[f];M[c]=m;
#define S second
using namespace std;typedef map<char,int>R;R D,P,M;struct U{U():t(0),l(0),a(0){}int t,l,a;operator int(){return t+l;}I&d(I&s){char c,b;s>>c;if(c=='('){s>>c>>b;T(b!=')')c+=32;}if(s){R::iterator f=D.find(c);T(f==D.end())if(P[c]==l){l=f->S-l;a=0;}else{T(l&&(f->S>l))a=l==f->S?a+1:1;T(a>M[c])t+=l;l=f->S;}}return s;}};I&operator>>(I&s,U&d){return d.d(s);}int main(){D[' ']=-1;X(73,1,32,3)X(86,5,73,1)X(88,10,73,3)X(76,50,88,1)X(67,100,88,3)X(68,500,67,1)X(77,1000,67,3)X(118,5000,77,1)X(120,10000,77,3)X(108,50000,120,1)X(99,100000,120,3)X(100,500000,99,1)X(109,1000000,99,3)string w;while(cin>>w){try{stringstream s(w);U c;while(s>>c);cout<<c<<"\n";}catch(int x){cout<<"0\n";}}}

มันอาจถูกบีบอัดเพิ่มเติม

> ./a.exe
III
3
IIII
0
XVI
16
(C)(D)(L)MMI
452001

การจัดรูปแบบ nicer เล็กน้อย: 1582 ถ่าน

#include<map>
#include<string>
#include<iostream>
#include<sstream>
#define I istream
#define T(C) if(C)throw int(1);
#define X(c,v,f,m) D[c]=v;P[c]=D[f];M[c]=m;
#define S second
using namespace std;

typedef map<char,int>      R;

R     D,P,M;

struct U
{
    U(): t(0), l(0), a(0) {}

    int  t,l,a;

    operator int()
    {
        return t + l;
    }
    I& d(I& s)
    {
        char c,b;
        s >> c;
        if (c == '(')
        {
            s >> c >> b;
            T(b != ')')
            c = tolower(c);
        }
        if (s)
        {
            R::iterator f = D.find(c);
            T(f == D.end())

            if (P[c] == l)
            {
                l = f->S - l;
                a = 0;
            }
            else
            {
                T(l&&(f->S > l))
                a=l==f->S?a+1:1;
                T(a>M[c])
                t   += l;
                l     = f->S;
            }
        }

        return s;
    }

};

I& operator>>(I& s,U& d)
{
    return d.d(s);
}

int main()
{
    D[' ']=-1;
    X(73,1,32,3)
    X(86,5,73,1)
    X(88,10,73,3)
    X(76,50,88,1)
    X(67,100,88,3)
    X(68,500,67,1)
    X(77,1000,67,3)
    X(118,5000,77,1)
    X(120,10000,77,3)
    X(108,50000,120,1)
    X(99,100000,120,3)
    X(100,500000,99,1)
    X(109,1000000,99,3)

    string w;
    while(cin >> w)
    {
        try
        {
            stringstream s(w);
            U    c;
            while(s >> c);
            cout << c << "\n";
        }
        catch(int x)
        {
            cout << "0\n";
        }
    }
}

ฉันไม่คิดว่าคุณต้องการช่องว่างระหว่างฟังก์ชั่นมาโครกับคำจำกัดความของพวกมัน
Zacharý

4

Javascript, 317 ตัวอักษร

function f(s){for(r=/\(?(.\)?)/g,t=e=0;a=r.exec(s);l=a[0].length,d='IXCMVLD'.indexOf(a[1][0]),e=e||d<0||l==2||d*4+l==3,t+='+'+(d>3?5:1)*Math.pow(10,d%4+3*(l>1)));t=t&&t.replace(/1(0*).(10|5)\1(?!0)/g,'$2$1-1$1');return e||/[^0](0*)\+(10|5)\1/.test(t)||/(\+10*)\1{3}(?!-)/.test(t)||/-(10*)\+\1(?!-)/.test(t)?0:eval(t)}

ชี้แจง:

function f(s){
      // iterate over every character grabbing parens along the way
  for(r=/\(?(.\)?)/g,t=e=0;a=r.exec(s);    
        // get a numerical value for each numeral and join together in a string
    l=a[0].length,
    d='IXCMVLD'.indexOf(a[1][0]),
    e=e||d<0||l==2||d*4+l==3,    // find invalid characters, and parens
    t+='+'+(d>3?5:1)*Math.pow(10,d%4+3*(l>1))
  );
      // reorder and subtract to fix IV, IX and the like
  t=t&&t.replace(/1(0*).(10|5)\1(?!0)/g,'$2$1-1$1');
  return e||
    /[^0](0*)\+(10|5)\1/.test(t)|| // find VV,IIV,IC,...
    /(\+10*)\1{3}(?!-)/.test(t)||  // find IIII,... but not XXXIX
    /-(10*)\+\1(?!-)/.test(t)      // find IVI,... but not XCIX
      ?0:eval(t)
}

ไม่มีการตรวจจับข้อผิดพลาดมันเป็นเพียง180 ตัวอักษร

function g(s){for(r=/\(?(.\)?)/g,t=0;a=r.exec(s);d='IXCMVLD'.indexOf(a[1][0]),t+='+'+(d>3?5:1)+'0'.repeat(d%4+3*(a[1].length>1)));return eval(t.replace(/(1(0*).(10|5)\2)/g,'-$1'))}

วิธีนี้ใช้งานได้เหมือนกัน แต่นี่เป็นรูปแบบที่ดีกว่า:

function g(s){
  for(r=/\(?(.\)?)/g,t=0;a=r.exec(s);
    d='IXCMVLD'.indexOf(a[1][0]),
    t+='+'+(d>3?5:1)+'0'.repeat(d%4+3*(a[1].length>1))
  );
  return eval(t.replace(/(1(0*).(10|5)\2)/g,'-$1'))
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.