【LeetCode13:罗马数字转整数(附Java、Python3代码)】

一、题目描述

1.题目内容

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数
原题链接:https://leetcode.cn/problems/roman-to-integer/
与此相反,LeetCode12:整数转罗马数字,可参考https://blog.csdn.net/qq_43665602/article/details/127318353

2.样例

在这里插入图片描述

二、解决方案

初步想法:

通过观察发现:
正常情况:一个基础罗马字符A对应一个数值NUM,比如I=1,V=5。对于连续字符串AB,此时NUM=B-A<=0,比如字符串VI,此时I-V=-4<0;
特殊情况:特殊情况下两个罗马字符AB构成一个数值NUM,且NUM=B-A>0。比如IV=V-I=4>0;

由此得到解题步骤:

  • 1.将基础罗马数字及其对应的数值构造映射关系存储;
  • 2.创建两个指针i,j分别指向两个相邻的字符,初始化i=0,j=1;
  • 3.比较字符串s,s[j]-s[i]对应的数值是否大于0,如果大于0,说明此时相邻两个字符可能构成特殊情况,左面字符小于右面字符:若为特殊情况,则此时i和j同时向右移动2个距离,否则说明此时i所指向的字符为基础字符,此时i,j向右移动1个距离;
  • 4.反之,如果s[j]-s[i]<=0,说明此时i所指向的字符为基础字符,此时i,j向右移动1个距离;

在代码实现时,有两个需要注意的点:

  • (1)除了6种特殊情况,其他的都是正常情况:通过判断s[j]-s[i]%100=4或s[j]-s[i]%100=9等条件是否满足,确定特殊情况
  • (2)因为如果遇到特殊情况,指针i和j同时向右移动两个位置,那么当传入字符串最后两个字符不构成特殊情况时,j会指向s.length的位置,也就是发生了数组越界,出现空指针异常。为了避免这种情况发生,需要在每次迭代开始时,判断一下j是否越界,如果越界则说明字符串最后的字符属于正常情况,直接处理i所指向的字符即可(如例2)
    举个例子:
    例1:
    在这里插入图片描述
    例2:
    在这里插入图片描述

1.Java代码

Java实现时,可以构建映射关系的数据结构,当属HashMap。

import java.util.HashMap;
import java.util.Map;

public class RomanToInt {
    public static int romanToInt(String s) {
        int num=0;
        String[] romanKey=new String[]{"I","V","X","L","C","D","M"};
        int[] intValue=new int[]{1,5,10,50,100,500,1000};
        Map<String,Integer> romanToInt=new HashMap<String,Integer>();
        for(int k=0;k<romanKey.length;k++) {
            romanToInt.put(romanKey[k],intValue[k]);
        }
//        System.out.println(romanToInt);

        int i=0;
        int j=1;
        while (i<s.length()){
            int difference=0;  // 计算相邻字符对应数值的差值
            if(j<s.length()) {
                difference = romanToInt.get(s.charAt(j) + "") - romanToInt.get(s.charAt(i) + "");
            }else {  // 当j移动到最后一次判断时有可能越界,此处用于避免空指针异常
                difference=romanToInt.get(s.charAt(i) + "");
            }
			
			// 判断特殊情况
            if(difference>0&&(difference%100==4||difference%100==9||difference%100==40||difference%100==90||difference%100==0)){
                // 如果符合六种特殊情况,则更新num,i和j同时向右移动2个距离;
                num+=difference;
                i+=2;
                j+=2;
            }else{  // 处理正常情况
                num+=romanToInt.get(s.charAt(i)+"");
                i+=1;
                j+=1;
            }
        }
        return num;
    }

    public static void main(String[] args) {
//        String s = "MCMXCIV";
        String s = "III";
//        String s = "LVIII";
//        String s = "IX";
//        String s = "IV";
        System.out.println(romanToInt(s));
    }
}

提交结果一发入魂:
在这里插入图片描述

2.Python代码

Python实现时,可以构建映射关系的数据结构,当属字典dict。

'''
LeetCode13:罗马数字转整数
'''


def roman_to_int(s):
    num = 0
    romanKey = ["I", "V", "X", "L", "C", "D", "M"]
    intValue = [1, 5, 10, 50, 100, 500, 1000]
    romanToInt ={}
    for k in range(0,len(romanKey)):
        romanToInt[romanKey[k]]=intValue[k]

    i=0
    j=1
    while i<len(s):
        if j<len(s):
            difference=romanToInt[s[j]]-romanToInt[s[i]]
        else:
            difference = romanToInt[s[i]]

        if difference>0 and (difference%100==4 or difference%100==9 or difference%100==40 or
                             difference%100==90 or difference%100==0 ):
            num+=difference
            i+=2
            j+=2
        else:
            num+=romanToInt[s[i]]
            i+=1
            j+=1
    return num


if __name__=='__main__':
    # s = "MCMXCIV"
    # s = "III"
    s = "LVIII"
    # s = "IX"
    # s = "IV"
    print(roman_to_int(s))

提交结果:
在这里插入图片描述

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NorthSmile

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值