• LeetCode 第12题:整数转罗马数字(Python3解法)


    1:问题描述

    来源:LeetCode

    难度:中等


    问题详情:
    罗马数字包含以下七种字符: IVXLCDM

    字符数值
    I I I1
    V V V5
    X X X10
    L L L50
    C C C100
    D D D500
    M M M1000

    例如, 罗马数字 2 写做 II ,即为两个并列的 112 写做 XII ,即为 X + II27 写做 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。

    给你一个整数,将其转为罗马数字。

    示例1

    输入:num = 3
    输出:“III”

    示例2:

    输入: num = 1994
    输出: “MCMXCIV”
    解释: M = 1000, CM = 900, XC = 90, IV = 4.

    提示

    1 < = n u m < = 3999 1 <= num <= 3999 1<=num<=3999


    2:问题分析

    2.1 时间复杂度和空间复杂度

    在真正开始介绍各种算法前,先以表格形式展示各自的时间复杂度和空间复杂度,其中 n n n表示字符串 s s s的长度。

    算法时间复杂度空间复杂度
    模拟 O ( 1 ) O(1) O(1) O ( 1 ) O(1) O(1)
    硬编码 O ( 1 ) O(1) O(1) O ( 1 ) O(1) O(1)
    自己的解法 O ( 1 ) O(1) O(1) O ( 1 ) O(1) O(1)

    2.2 模拟

    图片来源
    在这里插入图片描述
    我们先来看一下示例中的1994是如何转换成罗马数字的。
    首先数字1994被拆解成1000+900+90+4.
    可以看出每一位都是用选取尽可能大的数值。

    2.2.1 代码

    构建一个从大到小的元组对,遍历每一个元组对,如果当前num值大于等于当前元组中的数值key,那么就减去足够多的key,使 n u m < k e y numnum<key,同时减了多少次key,就要记录多少次key对应的罗马字符。
    直至 n u m = 0 num=0 num=0,循环结束。

    def intToRoman3(num: int) -> str:
        """对方法2中相减那一处的优化"""
        VALUE_SYMBOLS = [
            (1000, "M"),
            (900, "CM"),
            (500, "D"),
            (400, "CD"),
            (100, "C"),
            (90, "XC"),
            (50, "L"),
            (40, "XL"),
            (10, "X"),
            (9, "IX"),
            (5, "V"),
            (4, "IV"),
            (1, "I"),
        ]
        result = ''
        for key, value in VALUE_SYMBOLS:
            if num >= key:
                count = (num // key)
                num -= count * key
                result += count * value
            if num == 0:
                break
    
        return result
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    时间复杂度为 O ( 1 ) O(1) O(1),空间复杂度为 O ( 1 ) O(1) O(1)

    2.3 硬解码

    上述方案是从上图中的每一个“挡位”对应的罗马字符出发构建的。

    而硬解码的方案则是从num数值中每一位的角度出发。
    由提示可以得到,num值最多为3999;所以我们先从千位出发,考虑其能够取到的值,是1、2、3,然后构建其对应的罗马数字’M‘,'MM','MM';
    同理,我们构建了如下表格(表格来源):
    在这里插入图片描述

    2.3.1 代码

    代码如下:

    THOUSANDS = ["", "M", "MM", "MMM"]
    HUNDREDS = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"]
    TENS = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"]
    ONES = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]
    
    
    def intToRoman4(num: int) -> str:
        """硬编码,就是把每一位的所有可能都列出来,以空间换时间"""
        return THOUSANDS[num // 1000] + HUNDREDS[num % 1000 // 100] + TENS[num % 100 // 10] + ONES[num % 10
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    时间复杂度为 O ( 1 ) O(1) O(1),空间复杂度为 O ( 1 ) O(1) O(1)

    2.3 我的解法

    我的解法同样从每一位出发,但是不使用硬编码的形式,而是通过当前位数的数值分析其对应的罗马数字。

    比如百位中如果是9或者4,则对应的是'CM'’CD‘
    如果是7,则大于等于5的部分使用一个’D‘表示,不超过的部分即(7-5=2)使用’C‘×2表示;
    如果百位本身就是小于4的数,比如3,则直接使用’C‘×3表示;

    2.3.1 代码

    代码中构建了一个二维列表,每个元素中都存储了当前位数的两个对应的罗马字符。
    比如百位,第0个元素是’D‘,第1个元素是’C‘。

    def intToRoman(num: int) -> str:
        special = {9: 'IX', 4: 'IV', 40: 'XL', 90: 'XC', 400: 'CD', 900: 'CM'}
        index_str = [['V', 'I'], ['L', 'X'], ['D', 'C'], ['', 'M']]
        index = [3, 2, 1, 0]
        result = ''
        for i in index:
            cur, num = divmod(num, 10 ** i)
            if cur == 4 or cur == 9:
                result += special.get(cur * 10 ** i, '')
            elif 9 > cur >= 5:
                result += index_str[i][0]
                result += (cur - 5) * index_str[i][1]
            elif cur < 4:
                result += cur * index_str[i][1]
        return result
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    时间复杂度为 O ( 1 ) O(1) O(1),空间复杂度为 O ( 1 ) O(1) O(1)

  • 相关阅读:
    【华为OD机试真题 python】 5键键盘【2022 Q4 | 100分】
    机器学习笔记 - 深入研究spaCy库及其使用技巧
    [vue问题]开发中问题集合
    CC2642 OAD文件合成
    企业架构LNMP学习笔记55
    2022亚太赛题浅评
    MySQL基础
    百科源码生活资讯百科门户类网站百科知识,生活常识
    交互式多模型-无迹卡尔曼滤波IMM-UKF仿真一——机动目标跟踪中的应用
    土地利用强度(LUI)综合指数
  • 原文地址:https://blog.csdn.net/weixin_43490422/article/details/126735396