Зміст дописунатисність на посилання, щоб перейти до потрібного місця
Розглянемо простий варіант вирішення задачі по перетворенню римського числа на десяткове (Ruby).
Умова
Створіть функцію solution, яка приймає рядок — римське число — і повертає його значення як десяткове ціле число.
Валідацію правильності римського запису робити не потрібно.
Приклади:
- "MCMXC" → 1990
- "MMVIII" → 2008
- "MDCLXVI" → 1666
Як працює конвертація римських чисел у десяткові?
Римські числа — це система числення, що базується на символах, кожен з яких відповідає певному значенню: I — 1, V — 5, X — 10, L — 50, C — 100, D — 500, M — 1000. Для запису числа символи комбінуються за певними правилами. Якщо символ меншого значення стоїть перед більшим (наприклад, IV), це означає віднімання (5 - 1 = 4). Якщо ж навпаки — додаються (VI = 5 + 1 = 6). Завдяки такій логіці можна компактно записувати як прості числа, так і складні, як-от MCMXC для 1990.
При перетворенні римських чисел у десяткові комп’ютерний алгоритм проходить символи рядка справа наліво. Це дає змогу легко визначити, чи потрібно додати значення символа, чи відняти його. Наприклад, у XIV обробка починається з V = 5, потім I = 1 (менше за V, тому віднімаємо: 5 - 1 = 4), потім X = 10 (більше за I, тому додаємо: 10 + 4 = 14). Такий підхід дозволяє ефективно реалізувати перетворення навіть у кілька рядків коду.
Тест (rspec) для перевірки методу
RSpec.describe '#solution' do it 'перетворює прості римські числа' do expect(solution('I')).to eq(1) expect(solution('III')).to eq(3) expect(solution('VIII')).to eq(8) end it 'перетворює складені римські числа' do expect(solution('IV')).to eq(4) expect(solution('IX')).to eq(9) expect(solution('XL')).to eq(40) expect(solution('XC')).to eq(90) end it 'перетворює великі римські числа' do expect(solution('MCMXC')).to eq(1990) expect(solution('MMVIII')).to eq(2008) expect(solution('MDCLXVI')).to eq(1666) expect(solution('MMMCMXCIX')).to eq(3999) end end
Метод solution
Один з варіантів вирішення (за допомогою Ruby одні й ті самі штуки можна роботи багатьма способами).
def solution(roman) values = { 'M' => 1000, 'D' => 500, 'C' => 100, 'L' => 50, 'X' => 10, 'V' => 5, 'I' => 1 } total = 0 prev = 0 roman.chars.reverse.each do |char| current = values[char] if current < prev total -= current else total += current prev = current end end total end
Принцип роботи алгоритму
Ми рухаємось з кінця рядка, додаючи значення символів. Якщо поточне число менше за попереднє — віднімаємо його, інакше — додаємо. Це дозволяє коректно обробляти випадки на кшталт IV чи CM.