您的位置:首页 > 其它

LeetCode 12 Int2Roman && 13 Roman2Int

2015-08-01 00:23 253 查看
1.Integer to Roman

Given an integer, convert it to a roman numeral.

Input is guaranteed to be within the range from 1 to 3999.

解题思路:

首先,要搞清楚罗马数字命名规则,搞清规则之后下手,就非常容易。

3999以内的罗马数字主要由几个单字组成,I 、V、 X、 L、C、M。一般情况下,都是大的单字后面跟着小的单字,如VI VII 等,但是一旦小的单字在前面就表示减法,如IV(4)、CM(900)等等。为什么有减法规则?因为罗马数字命名规则要求单字不能重复出现超过3次。因此,有了减法规则。因此在构造罗马数字的时候,应该考虑所有会出现的单字以及减法单字。

3999以内的单字以及减法字如下:(两个数组,以索引映射)

int val[] = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };

String re[] = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };

借组上述规定,按照递减的办法将阿拉伯数减去上述的基数,每次递减字符串自加一个对应的罗马基数。直到阿拉伯数递减结果为0,则构造出罗马字。代码复杂度为O(n),实际上接近O(n^2),因为重置了i。

代码如下:C语言版,这个代码段让我复习了c语言的内存知识,之前没有用malloc分配内存(分配到堆上),而是直接定义在了函数栈空间当中,计算不能得到结果。

char* intToRoman(int num) {
unsigned int val[] = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
char* r[] = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
char *re = NULL;
re=(char*)malloc(sizeof(char*) * 20);
if (num > 3999 || num < 0) return re;
int i = 0;
while (num>0)
{
if (num>=val[i])
{
strcat(re, r[i]);
num -= val[i];
i = 0;
continue;
}
i++;
}
return re;
}
java版如下:相比于c语言的char数组,java的string就方便了许多。

public String intToRoman(int num) {
int val[] = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
String r[] = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
String re="";
if (num > 3999 || num < 0) return re;
int i = 0;
while (num>0)
{
if (num>=val[i])
{
re+=r[i];
num -= val[i];
i = 0;
continue;
}
i++;
}
return re;
}



2.Roman to Integer

Given a roman numeral, convert it to an integer.

Input is guaranteed to be within the range from 1 to 3999.
有了第一题的铺垫,这一题简单了许多,为了提高效率,利用map直接映射单字和阿拉伯数组的索引,当然要考虑双字符以及单字符的影响,对其进行判断。这里用了个map很cool的初始化方法,看上去非常舒服。
代码如下:

public int romanToInt(String s) {
int val[] = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
String re[] = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
HashMap<String,Integer> hm = new HashMap<String,Integer>(){
{   put("M", 1000);
put("CM", 900);
put("D", 500);
put("CD", 400);
put("C", 100);
put("XC", 90);
put("L", 50);
put("XL", 40);
put("X", 10);
put("IX", 9);
put("V", 5);
put("IV", 4);
put("I", 1);    } 	};
int n = s.length();
int i = 0;
int result=0;
while (i != n){
if(i<n-1){
String t = s.substring(i, i+2);
if(hm.get(s.substring(i, i+2))!=null){
result+=hm.get(t);
i+=2;
continue;
}
}
if(hm.get(s.substring(i,i+1))!=null){
result+=hm.get(s.substring(i,i+1));
}
i++;
}
return result;
}


实际上,上述算法因为是在java的情况下,没有发挥最好的性能,实际上利用c的char有着更好地性能,这里有个简洁的算法只考虑上述加减法的逻辑,当时我怎么没想到,掉到java封装的坑里了。

#define I 1
#define V 5
#define X 10
#define L 50
#define C 100
#define D 500
#define M 1000
int romanToInt(char* s) {
char pre = 'A';
char current = 'A';
int amount = 0;
for (int i = strlen(s) - 1; i >= 0; i--)
{
current = toupper(s[i]);
if (s[i] == 'I')
{
if (pre == 'V' || pre == 'X')
{
amount -= I;
}
else {
amount += I;
}
}
if (s[i] == 'V')
{
amount += V;
}
if (s[i] == 'X')
{
if (pre == 'L' || pre == 'C')
{
amount -= X;
}
else
{
amount += X;
}
}
if (s[i] == 'L')
{
amount += L;
}
if (s[i] == 'C')
{
if (pre == 'D' || pre == 'M')
{
amount -= C;
}
else
{
amount += C;
}
}
if (s[i] == 'D')
{
amount += D;
}
if (s[i] == 'M')
{
amount += M;
}
pre = current;
}
return amount;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: