【LeetCode12:整数转罗马数字(附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/integer-to-roman/
对应相反的题为LeetCode13:罗马数字转整数,可参考https://blog.csdn.net/qq_43665602/article/details/127307596

2.样例

在这里插入图片描述

二、解决方案

举几个例子先:

例1: 输入整数为num=3999,分析其计算过程: 3999=3000+900+90+9
其中3000=1000+1000+1000,而1000=M,900=CM,90=XC,9=IX
所以3000=MMM,3999=MMMCMXCIX

例2:输入整数为num=738,分析其计算过程:738=700+30+8
其中700=500+200=500+100+100,30=10+10+10,而8=5+3=5+1+1+1
所以700=DCCXXXVIII

观察分析:

(1)在题目中给定基础罗马字符共7个,即I、V、X、L、C、D、M;特殊情况共6种,为IV、IX、XL、XC、CD、CM,并说明了这13种情况各自对应的数值为多少。因此我们在进行代码实现时一定要注意遇到这13种情况必须严格按照其映射关系来处理,比如500=D而不是CCCCC。
(2)此外,将题目要求的整数区间划分为[1,10],[10,100],[100,1000]三个区间。可以看到在每个区间之内,以5或者50、500作为一个临界点,比如[1,10]区间中,5作为临界点。当某个数大于对应临界点时则需要进行分解,比如num=600,500<num<1000,那么此时我们需要将num拆分为500+100,即600=500+100=MC,而不是600=CCCCCC。

所以可推出:

代码实现时情况分为两种:

  • 属于事先说明的13种情况之一
  • 其他情况:在其他情况中,又分为两种子情况,通过此数值在对应区间是否超出临界点

由此得到我们代码实现的算法流程

  • 构建事先说明的13种情况之间的映射关系(比如Python中用字典结构存储);
  • 获取输入整数千百十个位,各自对应的数值,比如1338百位为3;
  • 分别对该数的各位置进行处理,进行罗马字符转换:(1)对于千位数值,直接累计1000所对应的罗马字符即可;(2)对于百十个位数值,在他们对应区间需要考虑两种情况:1)对应整数是否为13种情况之一;2)此数值在对应区间是否超出临界点;比如字符串为s,整数num=1338百位为second_num=3,说明需要在s中添加300对应的罗马字符串CCC,而个位forth_num=8>5,则说明需要分别添加5和3对应的字符,即V和III,依次类推得到1338=MCCCXXXVIII。

1.Python代码

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


class Solution:
	# 处理百十个位对应数字
    def process_num(self,map_relation,num,level)->str:
        s=''
        if num==9 or num==4 or num==1 or num==5:  # 13种情况之一
            s+=map_relation[num*level]
        else:
            if num>5:  # 超出临界点
                s+=map_relation[5*level]
                for i in range(0,num-5):
                    s+=map_relation[level]
            else:
                for i in range(0,num):
                    s+=map_relation[level]

        return s

    def intToRoman(self, num: int) -> str:
        # 构造数值与对应罗马字符串之间的映射关系,使用字典存储
        intKey = [1, 5, 10, 50, 100, 500, 1000,4,9,40,90,400,900]
        romanValue = ["I", "V", "X", "L", "C", "D", "M","IV","IX","XL","XC","CD","CM"]
        intToRoman ={}
        for k in range(0,len(intKey)):
            intToRoman[intKey[k]]=romanValue[k]

        # 分别得到输入数字的千百十个位对应数字
        first_num=int(num/1000)
        second_num=int(num/100%10)
        third_num=int(num/10%10)
        forth_num=int(num%10)

        # 分别处理千百十个位对应数值:
        s=''
        for i in range(0,first_num):  # 处理千位数字
            s+=intToRoman[1000]

        s+=self.process_num(intToRoman,second_num,100)
        s+=self.process_num(intToRoman,third_num,10)
        s+=self.process_num(intToRoman,forth_num,1)

        return s


if __name__=='__main__':
    num=1994
    # num=3
    # num=500
    # num=700
    # num=250
    # # num=5000
    # # num=4
    # num=3999
    print(Solution().intToRoman(num))

2.Java代码

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

public class IntToRoman {

    public static void main(String[] args) {
        int num=1994;
        Solution solution=new Solution();
        System.out.println(solution.intToRoman(num));
    }
}

class Solution{
    // 处理百十个位对应数字
    /*
    level表示处理百/十/个位,不同位置;
    level=1、level=10、level=100分别表示个十百位置
    * */
    public String  processNum(Map<Integer,String> mapRelation,int num,int level) {
        StringBuilder s = new StringBuilder();
        if (num == 9 || num == 4 || num == 1 || num == 5) {  // 13种情况之一
            s.append(mapRelation.get(num * level));
        } else {
            if (num > 5){ // 超出临界点
                s.append(mapRelation.get(5 * level));
                for (int i=0;i<num-5;i++) {
                    s.append(mapRelation.get(level));
                }
            }else {
                for (int i=0;i<num;i++) {
                    s.append(mapRelation.get(level));
                }
            }
        }

        return s.toString();
    }


    public String intToRoman(int num) {
        // 构造数值与对应罗马字符串之间的映射关系,使用字典存储
        int[] intKey = new int[]{1, 5, 10, 50, 100, 500, 1000, 4, 9, 40, 90, 400, 900};
        String[] romanValue = new String[]{"I", "V", "X", "L", "C", "D", "M", "IV", "IX", "XL", "XC", "CD", "CM"};
        Map<Integer, String> intToRoman_ = new HashMap<Integer, String>();
        for (int k = 0; k < intKey.length; k++) {
            intToRoman_.put(intKey[k], romanValue[k]);
        }
//        System.out.println(intToRoman_);
        //分别得到输入数字的千百十个位对应数字
        int first_num=num/1000;
        int second_num=num/100%10;
        int third_num=num/10%10;
        int forth_num=num%10;


        // 分别处理千百十个位对应数值:
        StringBuilder s=new StringBuilder();
        for (int i=0;i<first_num;i++)  // 处理千位数字
            s.append(intToRoman_.get(1000));

        s.append(processNum(intToRoman_,second_num,100));
        s.append(processNum(intToRoman_,third_num,10));
        s.append(processNum(intToRoman_,forth_num,1));

        return s.toString();
    }
}

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

NorthSmile

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

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

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

打赏作者

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

抵扣说明:

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

余额充值