Перевод числа в римскую нотацию

Задача:
Семь различных символов представляют римские цифры со следующими значениями:

Числа: Римсие числа:
I 1
V 5
X 10
L 50
C 100
D 500
M 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

Ссылка:
Ссылка на leetcode

Моё решение:

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

    while num > 0:
        for elem in reversed(roman_nums):
            if elem <= num:
                num -= elem
                result.append(roman_nums[elem])
                break

    return ''.join(result)

Вопрос:
У меня скорее возникает вопрос в постановке задачи, нежели как её решить. будет ли корректно добавлять в словарь такие значения (ключ: значение) как:

{4: 'IV', 9: 'IX'} # И так далее для 40, 90, 400 и 900.

Или стоит решить задачу по-другому? Без использования этих значений (ключ: значение)? Я имею ввиду, что могу попробовать определять какое число наиболее подходит на данный момент, и в случае, если это будет 4 или 9 (или 40, 90, 400, 900), собирать уже такую конструкцию как IV (и тп. для других случаев). Может, в этом и состоит суть задачи?


Ответы (1 шт):

Автор решения: pythonniy_chainik

Всё-таки решил попробовать использовать только те значения, что есть в таблице. Вот что получилось:

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) # Возращаем результат

Хоть это и абсолютно бесполезно, решил поставить себе такую задачу. Стоит понимать, что я занимаюсь программированием менее полугода, поэтому, возможно, ваше решение может быть намного более эффективнее. Я лишь попробовал реализовать свою логику теми знаниями, которые на данный момент у меня есть. Также сделал вариант где возможны такие комбинации как: 49, 55 (и так далее), но, его выложить пока не могу, возможно, позже.

→ Ссылка