必要条件
古代ローマ帝国は人類に輝かしい文明をもたらしましたが、彼らの数字の表現は実に煩雑で、特に大きな数を表すとなると、現在ではとても耐えられないようなものでした。これは、この表現を考案した人々の知性に問題があったわけではなく、当時、数字の0という概念を禁じていた宗教的な理由によるものです!ローマ数字の表現は、次の基本記号に依存しています: I -> 1 V -> 5 X -> 10 L -> 50 C -> 100 D -> 500 MD -> 500 M -> 1000 ここでは、1000までの数の表現のみを説明します。一つの記号はその回数だけ繰り返されます。最大3回まで繰り返します。例:CCCは300 XXは20を表しますが、150はLLLを表すのに使われず、このルールはI X C Mにのみ適用されます。隣接するレベルの大単位が右側にあり、小単位が左側にある場合、大単位から小単位を引くことを意味します。例:IXは9 IVは4 XLは40 49 = XLIX より多くの例については下の表を参照してください。i = 1 ii = 2 iii = 3 iv = 4 v = 5 vi = 6 vii = 7 viii = 8 ix = 9 x = 10 xi = 11 xii = 12 xiii = 13 xiv = 14 xv = 15 xvi = 16 xvii = 17 xviii = 18 xix = 19 xx = 20 xxi = 21 xxii = 22 xxix = 29 xxx = 30xxxiv = 34 xxxv = 35 xxxix = 39 xl = 40 l = 50 li = 51 lv = 55 lx = 60 lxv = 65 lxxx = 80 xc = 90 xciii = 93 xcv = 95 xcviii = 98 xcix = 99 c = 100 cc = 200 ccc = 300 cd = 400 d = 500 dc = 600DCC = 700 DCCC = 800 CM = 900 CMXCIX = 999 この問題の要求:ユーザがローマ数字の文字列を入力し、プログラムが対応する10進数表現を出力するプログラムを書きなさい。入力形式は次の通り:最初の行は整数nで、後に続くローマ数字がn個あることを示します。続く各行はローマ数字です。ローマ数字の大きさは999を超えません。 プログラムは、ローマ数字の対応する10進データであるn行を出力する必要があります。例えば、ユーザが 3 LXXX XCIII DCCII と入力した場合、プログラムは 80 93 207 と出力します。
解答
3つのメソッドに分かれていて、3つのメソッドは簡単なものから難しいものまであります。しかし、それはすべて暴力的な解法です。
- 引き算を構成する文字列を見つけ、引き算の前に足し算を終わらせるのは簡単です。
- 変換規則に従って文字列を繰り返します。
- 隣接するローマ数字は加算されます。
- 隣接するローマ数字は、左が右より小さい場合、右 - 左に等しくなります。
- アイデアは第2幕と同じですが、アルゴリズム的にはよりクリーンです。
import java.util.*;
/*この問題の要件は次のとおりである: ユーザーがローマ数字の文字列を入力し、対応する10進数表現を出力するプログラムを書きなさい
入力形式は次のとおりである:最初の行は整数nで、次のn個のローマ数字(n<100)。
以後は1行に1つのローマ数字とする。ローマ数字の大きさは999を超えない。
プログラムにはn行の出力が要求されるが、これはローマ数字に対応する10進数データである。*/
public class Test3 {
public static void main(String[] args) {
method1("XCV");
// method2("XCV");
// method3("XCV");
}
//引き算を構成する文字列を直接見つける
private static void method1(String lm) {
int sum =0;
//文字列を繰り返し処理し、もし存在すれば、その文字列に
for (int i = 0; i < lm.length(); i++) {
char c = lm.charAt(i);
if (c == 'I') sum += 1;
if (c == 'V') sum += 5;
if (c == 'X') sum += 10;
if (c == 'L') sum += 50;
if (c == 'C') sum += 100;
if (c == 'D') sum += 500;
if (c == 'M') sum += 1000;
}
//indexOF(V)変更された部分文字列のインデックスを返す
if (lm.indexOf("IV")>=0) sum -= 2;
if (lm.indexOf("IX")>=0) sum -= 2;
if (lm.indexOf("XL")>=0) sum -= 20;
if (lm.indexOf("CD")>=0) sum -= 200;
if (lm.indexOf("CM")>=0) sum -= 200;
if (lm.indexOf("XC")>=0) sum -= 20;
System.out.println(sum);
}
//それらをキーと値のペアにし、一つずつ繰り返し処理する。
private static void method2(String lm) {
//ローマ数字に値を割り当てる
Map<Character,Integer> map = new HashMap<>();
map.put('I',1);
map.put('V',5);
map.put('X',10);
map.put('L',50);
map.put('C',100);
map.put('D',500);
map.put('M',1000);
//数字を配列に分割する
//10進数値
int sum = 0;
char[] chars = lm.toCharArray();
//文字の配列を右から左にループする。,
for (int i = chars.length-1; i >= 1; i--) {
//インデックスの代わりにiの初期値を変更する方がよい。
//現在の値
int cur = map.get(chars[i]);
//前の
int left = map.get(chars[i - 1]);
//現在の値がleftより大きい場合、left-leftを引く。
//初めての場合は、次の式を変更する必要がある。
if (i == chars.length-1){
if (left < cur){
sum = sum + cur - left;
}else {
sum = sum +cur+ left;
}
}else{
if (left < cur){
sum = sum - left;
}else {
sum = sum + left;
}
}
}
System.out.println(sum);
}
//考え方は第2法と同じだが、アルゴリズム的に単純化されている。
private static void method3(String lm) {
HashMap<String, Integer> map=new HashMap<String, Integer>();
map.put("I", 1);
map.put("V", 5);
map.put("X", 10);
map.put("L", 50);
map.put("C", 100);
map.put("D", 500);
map.put("M", 1000);
int result=0;
for(int i=0;i<lm.length();i++){
//割り算の最後の桁の前の数字だけを数える。
if(i <= lm.length()-2){
//+""私のMapキーはString型なので、この効果は文字列に変えることである。
//左が右より小さければ引き、iが加えられる。+1,次の2つにスキップし、そうでなければ一度に1桁ずつ加算する。
if(map.get(lm.charAt(i)+"") < map.get(lm.charAt(i+1)+"")){
result += (map.get(lm.charAt(i+1)+"")-map.get(lm.charAt(i)+""));
i++;
}else{
result += map.get(lm.charAt(i)+"");
}
//最後の桁は直接加算される
}else{
result += map.get(lm.charAt(i)+"");
}
}
System.out.println(result);
}
}




