1、题目名称
Roman to Integer (罗马数字到阿拉伯数字的转换)
2、题目地址
https://leetcode.com/problems/roman-to-integer/
3、题目内容
英文:Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999.
中文:给出一个罗马数字,将它转换成整数。输入在1-3999之间。
4、题目分析
这个题目和题目#12(阿拉伯数字到罗马数字的转换)需要实现的功能相反,是将罗马数字转换为阿拉伯数字。关于罗马数字与十进制数字的规律,在 #12的解题方案 中已有说明,虽然罗马数字并不是明显的十进制数字,但每一位都有共同的规律可循。
5、解题方法1
根据罗马数字每个十进制位的共同规律,在解析罗马数字的时候,可以从高位到低位,逐位转换成阿拉伯数字。
例如,代表单位1的罗马数字为“I”,单位5为“V”,单位10为“X”,那1-10的罗马数字就是I、II、III、IV、V、VI、VII、VIII、IX、X。十位的情况就是把“I”换成“X”、把“V”换成“L”、把“X”换成“C”,从而得出10-100的罗马数字是X、XX、XXX、XL、L、LX、LXX、LXXX、XC、C。其余各位以此类推。
一个比较笨拙的Java实现代码如下:
/**
* 功能说明:LeetCode 13 - Roman to Integer
* 开发人员:Tsybius
* 开发时间:2015年8月3日
*/
public class Solution {
/**
* 罗马数字转换为阿拉伯数字
* @param s 被转换的罗马数字
* @return 转换后的阿拉伯数字
*/
public int romanToInt(String s) {
String[] temp;
String result = "";
//千位
temp = getArabicNumber(s, "M", " ", " ");
result += temp[0];
s = temp[1];
//百位
temp = getArabicNumber(s, "C", "D", "M");
result += temp[0];
s = temp[1];
//十位
temp = getArabicNumber(s, "X", "L", "C");
result += temp[0];
s = temp[1];
//个位
temp = getArabicNumber(s, "I", "V", "X");
result += temp[0];
s = temp[1];
return Integer.parseInt(result);
}
/**
* 将罗马数字的首位转换为阿拉伯数字(需要指定具体位的1、5、10三个字母)
* @param romanNumber 罗马数字
* @param one 一
* @param five 五
* @param ten 十
* @return 数组
* 第一项为输入罗马数字中最高位数对应的阿拉伯数字
* 第二项为删去该数字后剩余部分的罗马数字
*/
private String[] getArabicNumber(String romanNumber,
String one, String five, String ten) {
//9
if (romanNumber.length() >= 2 &&
romanNumber.substring(0, 2).equals(one + ten)) {
return new String[] { "9", romanNumber.substring(2) };
}
//8
if (romanNumber.length() >= 4 &&
romanNumber.substring(0, 4).equals(five + one + one + one)) {
return new String[] { "8", romanNumber.substring(4) };
}
//7
if (romanNumber.length() >= 3 &&
romanNumber.substring(0, 3).equals(five + one + one)) {
return new String[] { "7", romanNumber.substring(3) };
}
//6
if (romanNumber.length() >= 2 &&
romanNumber.substring(0, 2).equals(five + one)) {
return new String[] { "6", romanNumber.substring(2) };
}
//5
if (romanNumber.length() >= 1 &&
romanNumber.substring(0, 1).equals(five)) {
return new String[] { "5", romanNumber.substring(1) };
}
//4
if (romanNumber.length() >= 2 &&
romanNumber.substring(0, 2).equals(one + five)) {
return new String[] { "4", romanNumber.substring(2) };
}
//3
if (romanNumber.length() >= 3 &&
romanNumber.substring(0, 3).equals(one + one + one)) {
return new String[] { "3", romanNumber.substring(3) };
}
//2
if (romanNumber.length() >= 2 &&
romanNumber.substring(0, 2).equals(one + one)) {
return new String[] { "2", romanNumber.substring(2) };
}
//1
if (romanNumber.length() >= 1 &&
romanNumber.substring(0, 1).equals(one)) {
return new String[] { "1", romanNumber.substring(1) };
}
//0
return new String[] { "0", romanNumber };
}
}
6、解题方法2
因为上一个方法中存在相似代码重复使用的情况,因此可以尝试尽量用数组和循环减少代码行数。
Java代码如下:
/**
* 功能说明:LeetCode 13 - Roman to Integer
* 开发人员:Tsybius2014
* 开发时间:2015年8月3日
*/
public class Solution {
/**
* 罗马数字转换为阿拉伯数字
* @param s 被转换的罗马数字
* @return 转换后的阿拉伯数字
*/
public int romanToInt(String s) {
//罗马数字 1、5、10、50、100、500、1000
String romanNumber = "IVXLCDM ";
String[] temp; //临时数组
String result = ""; //计算结果
//循环千位、百位、十位、个位
for (int i = 6; i >= 0; i-=2) {
//获取1、5、10三个数字单位
String one = romanNumber.substring(i, i + 1);
String five = romanNumber.substring(i + 1, i + 2);
String ten = romanNumber.substring(i + 2, i + 3);
temp = getArabicNumber(s, one, five, ten);
result += temp[0];
s = temp[1];
}
return Integer.parseInt(result);
}
/**
* 将罗马数字的首位转换为阿拉伯数字(需要指定具体位的1、5、10三个字母)
* @param romanNumber 罗马数字
* @param one 一
* @param five 五
* @param ten 十
* @return 数组
* 第一项为输入罗马数字中最高位数对应的阿拉伯数字
* 第二项为删去该数字后剩余部分的罗马数字
*/
private String[] getArabicNumber(String romanNumber,
String one, String five, String ten) {
//罗马数字的长度
int[] romanNumber1to9Length = new int[] {
1, 2, 3, 2, 1, 2, 3, 4, 2
};
//罗马数字的构成
String[] romanNumber1to9 = new String[] {
one, one + one, one + one + one, one + five, five,
five + one, five + one + one, five + one + one + one, one + ten
};
//1-9的情况匹配
for (int i = 9; i >= 1; i--) {
int len = romanNumber1to9Length[i - 1];
String num = romanNumber1to9[i - 1];
if (romanNumber.length() >= len &&
romanNumber.substring(0, len).equals(num)) {
return new String[] {
String.valueOf(i), romanNumber.substring(len)
};
}
}
//无匹配情况,返回0
return new String[] { "0", romanNumber };
}
}
7、解题方法3
虽然罗马数字的书写规则较为复杂,但根据罗马数字“左加右减”的规律,可以构造出更简单的罗马数字转换阿拉伯数字的方法:即从右向左(从低位向高位)考察罗马数字,遇到比上一个数字大的数字就加上,遇到比上一个数字小的数字就减去。
Java代码如下:
import java.util.HashMap;
/**
* 功能说明:LeetCode 13 - Roman to Integer
* 开发人员:Tsybius2014
* 开发时间:2015年8月3日
*/
public class Solution {
/**
* 罗马数字转换为阿拉伯数字
* @param s 被转换的罗马数字
* @return 转换后的阿拉伯数字
*/
public int romanToInt(String s) {
HashMap hashMap = new HashMap();
hashMap.put('I', 1);
hashMap.put('V', 5);
hashMap.put('X', 10);
hashMap.put('L', 50);
hashMap.put('C', 100);
hashMap.put('D', 500);
hashMap.put('M', 1000);
int result = 0;
int temp = 0; //临时变量,用于判断加减
int weight = 0; //当前读取到的罗马数字的权重
for (int i = s.length() - 1; i >= 0; i--) {
weight = hashMap.get(s.charAt(i));
if (temp <= weight) {
result += weight;
temp = weight;
} else {
result -= weight;
temp = weight;
}
}
return result;
}
}
END