https://leetcode-cn.com/problems/roman-to-integer/Números romanos em números
inteiros
Os números romanos contêm os sete caracteres a seguir: I, V, X, L, C, D e M.
Valor do caractere
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
Por exemplo, o número romano 2 é escrito como II, que é dois paralelos 1. 12 é escrito como XII, que é X + II. 27 Escreva XXVII, que é XX + V + II.
Normalmente, o pequeno número em algarismos romanos fica à direita do grande número. Mas há casos especiais, por exemplo, 4 não está escrito como IIII, mas IV. O número 1 está à esquerda do número 5 e o número representado é igual ao número 4 obtido pela redução do número 1 pelo número 5. Da mesma forma, o número 9 é representado como IX. Esta regra especial se aplica apenas às seis situações a seguir:
Eu posso ser posicionado à esquerda de V (5) e X (10) para representar 4 e 9.
X pode ser colocado à esquerda de L (50) e C (100) para indicar 40 e 90.
C pode ser colocado à esquerda de D (500) e M (1000) para indicar 400 e 900.
Dado um número romano, converta-o para um número inteiro. A entrada deve estar no intervalo de 1 a 3999.
Exemplo 1:
Entrada: "III"
Saída: 3
Exemplo 2:
Entrada: "IV"
Saída: 4
Exemplo 3:
Entrada: "IX"
Saída: 9
Exemplo 4:
Entrada: "LVIII"
Saída: 58
Explicação: L = 50, V = 5, III = 3.
Exemplo 5:
Entrada: "MCMXCIV"
Saída: 1994
Explicação: M = 1000, CM = 900, XC = 90, IV = 4.
Solução 1
Use o mapa.
A chave é uma única letra de algarismos romanos e val é o valor correspondente.
Necessidades para determinar a tecla correspondente ao que é agora val não é menos do que a próxima tecla val correspondente, como IV
quatro em vez de seis.
40ms 9.1mb, leva tempo para construir o mapa, a seguinte complexidade de tempo de operação é O (n).
class Solution {
public:
int romanToInt(string s) {
map<char, int> m = {
{'I', 1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000},
};
int ret = 0;
for (int i = 0; i < s.size(); ++i) {
if (m[s[i]] < m[s[i + 1]]) {
ret = ret - m[s[i]];
} else {
ret = ret + m[s[i]];
}
}
return ret;
}
};
Solução 2
A solução dos internautas é 4ms 5.6mb,
#define nI 1 //直接用define I 1,好像会有歧义
#define nV 5
#define nX 10
#define nL 50
#define nC 100
#define nD 500
#define nM 1000
int romanToInt(char* s)
{
int num = 0, flag = 0; /*立一个flag,是因为之前我在后面会用三个if,一个else,其实我的初衷是三个if有其中任何一个满足都不要再执行else了
但是如果没有flag的话,意思是第三个if如果不成立便会跳去else,比如IV,第一个if满足,然后第三个if不满足,else这时候
就会出来执行,很不爽*/
while(*s != NULL)
{
if(*s == 'I' && (*(s + 1) == 'V' || *(s + 1) == 'X')) //接下来的这三个if都有特殊含义,所以flag=1,普通情况属于flag=0
{
flag = 1;
switch(*(s + 1))
{
case 'V':num += (nV - nI); s+=2; break;
case 'X':num += (nX - nI); s+=2; break;
}
}
if(*s == 'X' && (*(s + 1) == 'L' || *(s + 1) == 'C'))
{
flag = 1;
switch(*(s + 1))
{
case 'L':num += (nL - nX); s+=2; break;
case 'C':num += (nC - nX); s+=2; break;
}
}
if(*s == 'C' && (*(s + 1) == 'D' || *(s + 1) == 'M'))
{
flag = 1;
switch(*(s + 1))
{
case 'D':num += (nD - nC); s+=2; break;
case 'M':num += (nM - nC); s+=2; break;
}
}
if(flag == 0) //本来这里是else的,改为if(flag == 0)
{
switch(*s)
{
case 'I':num += nI; s += 1; break;
case 'V':num += nV; s += 1; break;
case 'X':num += nX; s += 1; break;
case 'L':num += nL; s += 1; break;
case 'C':num += nC; s += 1; break;
case 'D':num += nD; s += 1; break;
case 'M':num += nM; s += 1; break;
}
}
flag = 0; //最后置回普通状态
}
return num;
}
EOF