给出一个罗马数,将其转换为整数.

保证范围为1-3999.

源代码

罗马数字采用七个罗马字母作数字、即Ⅰ(1)、X(10)、C(100)、M(1000)、V(5)、L(50)、D(500)

计数方式 : 百度百科维基百科

  • 重复数次:一个罗马数字重复几次,就表示这个数的几倍。如 Ⅲ=3
  • 右加左减

    • 小的数字在大的数字的右边,所表示的数等于这些数字相加得到的数,如 Ⅷ=8、Ⅻ=12
    • 小的数字(限于 Ⅰ、X 和 C)在大的数字的左边,所表示的数等于大数减小数得到的数,如 Ⅳ=4、Ⅸ=9
    • 右加数字不可连续超过三位,比如14写成XIV,而非XIIII。
    • 左减数字必须为一位,比如8写成VIII,而非IIX。
  • 在罗马数字的上方加上一条横线或者加上下标的Ⅿ,表示将这个数乘以1000,即是原数的1000倍,如果上方有两条横线,即是原数的1000000倍。

  • 数码限制:
    • 同一数码最多只能连续出现三次,如40不可表示为XXXX,而要表示为XL
      Roman Numerals Chart

实现

1.通过枚举(enum)

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
enum Roman: String {
case I, V, X, L, C, D, M
func getRomanValue() -> Int {
switch self {
case .I:
return 1
case .V:
return 5
case .X:
return 10
case .L:
return 50
case .C:
return 100
case .D:
return 500
case .M:
return 1000
}
}
//判断是否这三种类型,如果左边为三种则减
func isSubtract() -> Bool {
switch self {
case .I,.X,.C :
return true
default:
return false
}
}
}
//0.根据索引获取字符串当前索引字符
extension String {
func characterAtIndex(index: Int) -> Character? {
var cur = 0
for char in self.characters {
if cur == index {
return char
}
cur += 1
}
return nil
}
}
//罗马数 -> 整数
class Solution {
static func romanToInt(s: String) -> Int {
var intValue = 0
if s.characters.count == 1 {
return Roman(rawValue: s)!.getRomanValue()
}
//1.
let c_reversed = s.characters.reversed()
for (index,c) in c_reversed.enumerated() {
if (index+1) % 2 == 0 {
continue
}
let roman_after = Roman(rawValue: String.init(c))
//2.
if (index+1 == s.characters.count) {
return roman_after!.getRomanValue()+intValue
}
let c_curr = String(c_reversed).characterAtIndex(index: index+1)!
let roman = Roman(rawValue: String.init(c_curr))
//3.
if ((roman_after!.getRomanValue() > roman!.getRomanValue()) && roman!.isSubtract())
{
intValue = intValue + roman_after!.getRomanValue() - roman!.getRomanValue()
}else
{
intValue = intValue + roman_after!.getRomanValue() + roman!.getRomanValue()
}
}
return intValue
}
}
  1. 反转字符为字符数组.目的: 使罗马数从右向左依次计算
  2. 判断如果为最后一个,则整合全部的数
  3. 通过判断左边的字符值和右边的字符值比较大小,并且左边的字符符合罗马数I、X、L 时,则大的减去小的

以上的枚举通过使用字典存储

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
class Solution1 {
var romanDic: [String: Int] = ["I": 1,
"V": 5,
"X": 10,
"L": 50,
"C": 100,
"D": 500,
"M": 1000]
func romanToInt(s: String) -> Int {
if s.characters.count == 1 {
return romanDic[s] == nil ? romanDic[s]! : 0
}
//1.
let c_reversed = s.characters.reversed()
var intValue = 0
for (index,c) in c_reversed.enumerated() {
if (index+1) % 2 == 0 {
continue
}
let c_after_value = romanDic[String(c)]!
if (index+1) == s.characters.count{
return c_after_value + intValue
}
let c_curr = String(c_reversed).characterAtIndex(index: index+1)!
let c_curr_value = romanDic[String(c_curr)]!
if (c_after_value > c_curr_value) && (c_curr_value == 1 || c_curr_value == 10 || c_curr_value == 100){
intValue = intValue + c_after_value - c_curr_value
}else
{
intValue = intValue + c_after_value + c_curr_value
}
}
return intValue
}
}
  1. 对于根据索引获取字符串中的字符同样可以使用
    index(_ i: String.Index, offsetBy n: String.IndexDistance) -> String.Index 获取得到
1
2
3
4
let s = "Swift"
let i = s.index(s.startIndex, offsetBy: 4)
print(s[i])
// Prints "t"

测试:

使用一些特殊的罗马数进行测试:

XIV -> 14