RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1605779
Accepted
pythonniy_chainik
pythonniy_chainik
Asked:2025-01-28 23:35:18 +0000 UTC2025-01-28 23:35:18 +0000 UTC 2025-01-28 23:35:18 +0000 UTC

需要对用罗马数字系统表示十进制数的问题的解决方案进行代码审查

  • 772

问题:
七个不同的符号代表罗马数字,其含义如下:

罗马数字 十进制数
我 1
五 5
十 10
大号 50
碳 100
德 500
米 1000

罗马数字是由十进制数值从最高位到最低位相加转换而成的。小数位数值转换为罗马数字有以下规则:

如果值不是以 4 或 9 开头,请选择可以从输入中减去的最大值的符号,将该符号添加到结果中,减去其值,然后将余数转换为罗马数字。

如果值以 4 或 9 开头,则使用减法形式,表示从下一个符号中减去一个符号,例如 4 减 1(I)小于 5(V):IV,9 减 1(I)小于 10(X):IX。仅使用以下减法形式:4 (IV)、9 (IX)、40 (XL)、90 (XC)、400 (CD) 和 900 (CM)。

只有 10 的幂(I、X、C、M)可以连续添加不超过 3 次,以表示 10 的倍数。不能多次添加 5 (V)、50 (L) 或 500 (D)。如果需要将某个符号加 4 次,请使用减法形式。

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

示例 1:

Ввод: число = 3749

Вывод: "MMMDCCXLIX"

Объяснение:

3000 = МММ как 1000 (М) + 1000 (М) + 1000 (М)
 700 = DCC как 500 (D) + 100 (C) + 100 (C)
  40 = XL как 10 (X) меньше 50 (L)
   9 = IX как 1 (I) меньше 10 (X)
Примечание: 49 не на 1 (I) меньше 50 (L), поскольку преобразование основано на десятичных знаках.

示例 2:

Ввод: число = 58

Вывод: "LVIII"

Объяснение:

50 = L, 8 = VIII

示例 3:

Ввод: число = 1994

Вывод: "MCMXCIV"

Объяснение:

1000 = М
 900 = СМ
  90 = ХС
   4 = IV

限制:

1 <= num <= 3999

链接:
https://leetcode.com/problems/integer-to-roman/description/

我最近为这个任务写了一些代码。关键特性是我决定不向表中不存在的元组添加值(None 除外)。结果如下:

def int_to_roman(num):
    result = []
    nums = (1000, 500, 100, 50, 10, 5, 1, None)
    roman_nums = ('M', 'D', 'C', 'L', 'X', 'V', 'I')

    while not num == 0:
        for max_deductible in nums:
            # Находим такое наибольшее вычитаемое, которое будет меньше либо равно num
            if max_deductible <= num:
                # Сохраняем индекс вычитаемого
                max_deductible_index = nums.index(max_deductible)
                break

        # Сохраняем предыдущее число (до max_deductible)
        previous_num = nums[max_deductible_index - 1]
        flag = len(str(max_deductible)) == len(str(previous_num))

        # Выбор вычитаемого из next_num, которое подходит для данного случая
        possibly_deductible = (nums[max_deductible_index + 1], max_deductible)[flag]

        # Если существует число менее num и более max_deductible (в nums)
        if all((possibly_deductible, previous_num)) and previous_num - possibly_deductible <= num:
            num -= (previous_num - possibly_deductible)
            possibly_deductible_index = nums.index(possibly_deductible)

            # В римском вычитании сначала ставится вычитаемое, а потом уменьшаемое
            result.append(roman_nums[possibly_deductible_index] +
                          roman_nums[max_deductible_index - 1])
        else: # Если такого числа не существует, вычитаем max_deductible
            num -= max_deductible
            result.append(roman_nums[max_deductible_index])

    return ''.join(result) # Возращаем результат

我很乐意听到任何批评。但重要的是要明白,我最近才进入这个领域,因此我不应该建议任何来自库/框架的功能或方法。

python
  • 1 1 个回答
  • 147 Views

1 个回答

  • Voted
  1. Best Answer
    Vitalizzare
    2025-01-29T18:54:33Z2025-01-29T18:54:33Z

    总体评论:评论很单薄,缺乏需要讨论的领域。

    def int_to_roman(num):
    

    最好指定参数和返回值的类型。为什么不在声明之后写一行文档呢?

        result = []
        nums = (1000, 500, 100, 50, 10, 5, 1, None)
        roman_nums = ('M', 'D', 'C', 'L', 'X', 'V', 'I')
    

    None对最后的存在进行评论是正确的nums,但其必要性并不明显。

        while not num == 0:
    

    该条件包含限制1 <= num <= 3999。您还未获得验证。为什么?

            for max_deductible in nums:
                # Находим такое наибольшее вычитаемое, которое будет меньше либо равно num
                if max_deductible <= num:
                    # Сохраняем индекс вычитаемого
                    max_deductible_index = nums.index(max_deductible)
                    break
    

    首先,变量名中的“deductible”一词选择不当,因为它暗示与金融或保险有关,但这不是你的情况。考虑中性的替代方案,例如可减的。

    其次,可以(并且应该)通过逐渐降低值来消除这种循环nums。但是如果您使用它,那么可能就会使用它enumerate以避免寻找索引。关于为什么你不应该担心比较的评论也是恰当的None < num。

            # Сохраняем предыдущее число (до max_deductible)
            previous_num = nums[max_deductible_index - 1]
    

    在这里,评论可能会更有意义,指出索引失败的情况-1。

            flag = len(str(max_deductible)) == len(str(previous_num))
            # Выбор вычитаемого из next_num, которое подходит для данного случая
            possibly_deductible = (nums[max_deductible_index + 1], max_deductible)[flag]
    

    一个非常奇怪的地方,其名字的选择具有误导性flag。我认为这个变量的存在本身就没有道理;最好使用if ... else ...。对这个案例进行评论也是有用的len('1000') == len('None'),因为这种巧合太过牵强,而且不是通过算法计算出来的。

            # Если существует число менее num и более max_deductible (в nums)
            if all((possibly_deductible, previous_num)) and previous_num - possibly_deductible <= num:
    

    如果我正确理解了该算法,它if all((possibly_deductible, previous_num)) and ...归结为if previous_num is not None and ...。这句话的评论很奇怪;它让人困惑而不是解释。

                num -= (previous_num - possibly_deductible)
                possibly_deductible_index = nums.index(possibly_deductible)
    
                # В римском вычитании сначала ставится вычитаемое, а потом уменьшаемое
                result.append(roman_nums[possibly_deductible_index] +
                              roman_nums[max_deductible_index - 1])
    

    有争议的地方。如果我们将该类型的表达视为'IV', 'IX', 'XL', ...一位数字,以两个字素的组合来呈现,那就没有任何抱怨了。如果我们将这些表达式视为两个罗马数字的组合,那么您就隐式地复制了一组数字的最终组合。我认为,我们不应该只做一个,而append应该把两个数字接在一起,以消除数字之间隐藏的联系。

            else: # Если такого числа не существует, вычитаем max_deductible
                num -= max_deductible
                result.append(roman_nums[max_deductible_index])
    

    如果返回值是罗马数字首尾相连的字符串,则通过添加对来删除整个检查(900, 'CM'), (400, 'CD'), (90, 'XC'), ...。

        return ''.join(result) # Возращаем результат
    

    最后一条评论没有什么帮助。


    总体来说,算法比较清晰。考虑到上述评论,可以通过添加类型的符号进行优化'IV', 'XL', 'CD', ...。由于它们的数量很少,因此通过算法计算它们毫无意义:

    def int_to_roman(num: int) -> str:
        """Return the Roman representation of the given number between 1 and 3999 including.
        Examples:
        >>> int_to_roman(3749)
        'MMMDCCXLIX'
        >>> int_to_roman(1994)
        'MCMXCIV'
        >>> int_to_roman(58)
        'LVIII'
        >>> int_to_roman(0)    # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        AssertionError
        """
        assert 1 <= num <= 3999    # unalterable alternative: if not (1 <= num <= 3999): raise ValueError()
        result = []
        base_numbers = (1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1)
        roman_codes = ('M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I')
        base_code = zip(base_numbers, roman_codes)
        base, roman = next(base_code)
        while num > 0:
            while base > num:
                base, roman = next(base_code)
            num -= base
            result.append(roman)
        return ''.join(result) 
    
    if __name__ == '__main__':
        import doctest
        doctest.run_docstring_examples(int_to_roman, None)
    

    如果由于某种原因,编码表需要限制为简单数字,则可以对原始算法进行如下编辑:

    def int_to_roman(num: int) -> str:
        """Return the Roman representations for num in the interval [1, 3999]
        >>> int_to_roman(3749)
        'MMMDCCXLIX'
        >>> int_to_roman(1994)
        'MCMXCIV'
        >>> int_to_roman(58)
        'LVIII'
        """
        assert 1 <= num <= 3999 
        result = []
        base = (1000, 500, 100, 50, 10, 5, 1)
        code = ('M', 'D', 'C', 'L', 'X', 'V', 'I')
        step = 0
        while num > 0:
            # Находим такое наибольшее вычитаемое, которое будет меньше либо равно num
            while base[step] > num:
                # Сохраняем индекс вычитаемого            
                step += 1
            # Выбор вычитаемого из next_num, которое подходит для данного случая       
            shift = step%2            
            # Если существует число менее num и более max_deductible (в nums) 
            if step > 0 and num >= (diff:=base[step-1] - base[step+shift]):
                num -= diff
                # В римском вычитании сначала ставится вычитаемое, а потом уменьшаемое
                result.append(code[step+shift])
                result.append(code[step-1])
            else: # Если такого числа не существует, вычитаем max_deductible
                num -= base[step]
                result.append(code[step])
        return ''.join(result)
    

    保留原始注释以便与源代码进行比较。重大变化:

    1. 从参考数字中删除None,而是我们检查step > 0。
    2. 根据当前持仓的奇偶性计算偏移到相同订单的最小数字(例如:500->100 为 1,100->100 为 0)。
    • 1

相关问题

  • 是否可以以某种方式自定义 QTabWidget?

  • telebot.anihelper.ApiException 错误

  • Python。检查一个数字是否是 3 的幂。输出 无

  • 解析多个响应

  • 交换两个数组的元素,以便它们的新内容也反转

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5