Leetcode #13 Roman to Integer

Source: https://leetcode.com/problems/roman-to-integer/

13. Roman to Integer

Given a roman numeral,convert it to an integer.

Input is guaranteed to bewithin the range from 1 to 3999.

 

Solution:

       为了解决这个问题,首先我们需要了解罗马数字(即题目中的Roman)计数规则。

1 罗马数字采用七个罗马字母作数字,这些字母及其对应的数字依次是I(1)、V(5)、X(10)、L(50)、C(100)、D(500)、M(1000);

2 同一字母连续出现最多3次;

3 右加左减:

 (1) 在较大的罗马数字的右边记上较小或相等的罗马数字,表示大数字加小数字 (e.g. XI=11);

 (2) 在较大的罗马数字的左边记上较小的罗马数字,表示大数字减小数字 (e.g. IX=9);

  这里有以下限制:

  ① 左减数字只能有1位 (e.g. 8不可表示为IIX,而应是VIII);

  ② 左减数字只能是I、X、C之一 (e.g. 45不可表示为VL,而应是XLV);

  ③ 左减数字不能比其右一位低2位 (e.g. 99不可表示为IC,而应是XCIX)。

       罗马数字还有一些其他的规则,但是本问题的数字范围在1到3999之间,以上规则已经适用,故不作补充。

(以上规则整理自https://www.douban.com/note/335254352/

 

       如果我们以ans作为一个罗马数字形式的字符串所对应的值的十进制表达,从以上规则可以总结,在计算ans的过程中,罗马数字的各位所对应的值或加到ans中,或从ans中减去,具体是加是减,取决于这一位的下一位是否大于该位。因此可以较为轻松得到本题的解法如下,算法复杂度为O(n),空间复杂度为O(1),n为字符串的长度。

 

class Solution {
public:
    int romanToInt(string s) {
	    int i=0,j,k;
	    while (s[i]!='\0') //计算字符串长度
		    i++;
	    const int length=i;
	    char romanDigit[8]="IVXLCDM";
	    int weight[7]={1,5,10,50,100,500,1000};
	    int ans=0;
	    for (i=0;i<length-1;i++)
	    {
		    j=0;
		    k=0;
		    while (romanDigit[j]!=s[i]) //匹配该位
			    j++;
		    while (romanDigit[k]!=s[i+1]) //匹配下一位
		    	k++;
		    if (j<k) //判断该位是否小于下一位
			    ans=ans-weight[j];
		    else
			    ans=ans+weight[j];
	    }
	    i=0;
	    while (s[length-1]!=romanDigit[i]) //加上最后一位
	        i++;
	    ans=ans+weight[i];
	    return ans;
    }
};

       这一方法通过所有样例所需时间为32ms。我采用的另一种复杂得多的写法占用多一些空间,通过所有样例时间为22ms,本质思路没有改变,只不过将含有“左减”情况的两位罗马数字看成一个单位考虑。这里只贴上代码:

class Solution {
public:
    int romanToInt(string s) {
        int i=0,j=6,k;
	    int ans=0;
	    int weight[7]={1,5,10,50,100,500,1000};
	    int count[7]={0};
	    char romanDigit[8]="IVXLCDM";
	    
	    while (s[i]!='\0')
	        i++;
	    const int length=i;
	    
	    for (i=0;i<length;i++)
	    {
		    switch (s[i])
		    {
			    case 'I':
				    count[0]++;
				    break;
			    case 'V':
				    count[1]++;
				    break;
			    case 'X':
				    count[2]++;
				    break;
			    case 'L':
				    count[3]++;
				    break;
			    case 'C':
				    count[4]++;
				    break;
			    case 'D':
				    count[5]++;
				    break;
			    case 'M':
				    count[6]++;
				    break;
		    }
	    }

	    for (i=0;i<length;i++)
	    {
		    while (count[j]==0)
		    	j--;
			if (s[i]!=romanDigit[j])
		    {
		    	k=j-(2-(j%2));
				ans=ans+weight[j]-weight[k];
		    	count[j]--;
		    	count[k]--;
		    	i++;
		    }
		    else
		    {	
				ans=ans+weight[j];
				count[j]--;
			}
	    }
	    return ans;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值