[자바JAVA]13. Roman to Integer

문제 13. Roman to Integer

로마숫자를 아라비아숫자로 나타내는 문제이다.
Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.

For example, 2 is written as II in Roman numeral, just two one’s added together. 12 is written as XII, which is simply X + II. The number 27 is written as XXVII, which is XX + V + II.

Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:

I can be placed before V (5) and X (10) to make 4 and 9.
X can be placed before L (50) and C (100) to make 40 and 90.
C can be placed before D (500) and M (1000) to make 400 and 900.
Given a roman numeral, convert it to an integer.

  • 입출력 예시

https://koromoon.blogspot.com/2018/02/roman-numerals.html




첫번째 풀이 코드

입력값을 split으로 자른다음 역순으로 접근했다.
i를 먼저 반복문 돌린 뒤 예외사항들을 if조건문+swich case문으로 해결했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class Solution {
public int romanToInt(String s) {
int result = 0;
String[] chars = s.split("");

for(int i= chars.length-1; i>=0; i--) {
boolean isException = false;

if (i != chars.length - 1){
switch (chars[i]){
case "I":
if (chars[i + 1].equals("V") || chars[i+1].equals("X")){
isException = true;
result -= 1;
}
break;
case "X":
if (chars[i + 1].equals("L") || chars[i+1].equals("C")){
isException = true;
result -= 10;
}
break;
case "C":
if (chars[i + 1].equals("D") || chars[i+1].equals("M")){
isException = true;
result -= 100;
}
break;
}
}

if(!isException){
switch (chars[i]){
case "I":
result += 1;
break;
case "V":
result += 5;
break;
case "X":
result += 10;
break;
case "L":
result += 50;
break;
case "C":
result += 100;
break;
case "D":
result += 500;
break;
case "M":
result += 1000;
break;
}
}
}//end of for
return result;
}
}

for문 안에 if문 그 안에 swich문 그 안에 또 if문으로 굉장히 복잡하다.
3번의 들여쓰기가 있다면 코드를 되돌아보라는 유명한 코딩격언이 있다.
따라서 다시 방법을 생각해보고 구글링해보았다.




더 나은 풀이 코드

역순으로 접근하는 법은 동일하지만 삼항연산자로 훨씬 깔끔하다.
배열을 사용하지 않고 charAt()을 인덱스를 사용했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public int romanToInt(String s) {
int num = 0;
int len = s.length();
char c;

for (int i = len - 1; i >= 0; i--) {
c = s.charAt(i);
if (c == 'I') {
num += (num >= 5 || num >= 10) ? -1 : 1;
} else if (c == 'V') {
num += 5;
} else if (c == 'X') {
num += (num >= 50 || num >= 100) ? -10 : 10;
} else if (c == 'L') {
num += 50;
} else if (c == 'C') {
num += (num >= 500 || num >= 1000) ? -100 : 100;
} else if (c == 'D') {
num += 500;
} else if (c == 'M') {
num += 1000;
}
}
return num;
}
}




두 코드 차이점

두 코드에는 확실한 차이가 있다.

Runtime Memory
첫번째 풀이 15 ms 39.8 MB
더 나은 풀이 3 ms 38.8 MB




배운 지식

보자마자 switch case문이 생각나서 어떻게든 적용해보려고 노력했다.
swich case가 쉽다고 생각했는데 반복문을 대체할 수 있는 방법이 어떤 것이 있을까 생각하게되었다.
String이면 이 문제처럼 charAt()로 접근할 수도 있다.

런타임이 5배가 차이나는 이유가 무엇일까?

  • 내가 생각한 이유
    • 처음 접근법은 for문 + if문 + swich문 + if문 이렇게 중첩
    • 두번째 접근법은 for + if ~else
  • 멘토님이 말해주신 런타임이 5배 차이나는 이유

성능에서 차이가 발생한 점은 if - else나 switch의 조건 차이가 아니라
String[] chars = s.split(“”);
요놈 때문에 발생한 차이일거에요.
조건문은 아무리 깊어져도 성능에 크게 영향을 주지 않습니다

멘토님이 자료구조에 대해 더 공부하면 좋겠다고 말씀해주셨다.
자료구조는 기본소양!이니까
자료구조 항상 어려워서 어떻게 공부하면 좋을까 생각만하고있었다.
찾아보니 교과서인 생활코딩에서 자료구조 입문강의가 있었다. 이를 함께 공부해야겠다.




다른 문제 풀이가 보고싶다면?