LeetCode 12 Int2Roman && 13 Roman2Int

本文详细介绍了如何将整数转换为罗马数字以及如何从罗马数字解析整数的方法,包括了算法实现、性能优化和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值