leetcode12:整数转罗马数字

马数字包含以下七种字符: I, V, X, L,C,D 和 M。
更新于: 2021-12-19 12:57:29

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/integer-to-roman
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

描述

例如, 罗马数字 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。
给你一个整数,将其转为罗马数字。

 

提示

  • 1 <= num <= 3999

 

示例对应表

字符 数值说明
I1基本组成原子
II21+1
III31+1+1
IV45-1
V5基本组成原子
IX910-1
X10基本组成原子
L50基本组成原子
C100基本组成原子
D500基本组成原子
M1000基本组成原子

问题分析

  1. 列出所有的基本组成原子(参考上表) ATOM_MAP
  2. 将输出整数进行位数分解: 百、千、万等,注意十以及,十以下得先判断
    1. 分比对 1e5/1e5… 等进行取余,得到余数即可
    2. 结果存数组中
  3. 各种逻辑列举
    1. 1-9: fn1
    2. 10-99: fn2
    3. 100-999: fn3
    4. 1000-999: fn4
  4. 判断结果放进数组
  5. 数组转字符串输出

准备数据

var mapping = {
  1: ["I", "V"],
  2: ["X", "L"],
  3: ["C", "D"],
  4: ["M", "Z"],
};

1-9实现

// [1-9]
// I II III IV V VI VII VIII IX
function fn1(num) {
  const map1 = mapping[1];
  const map2 = mapping[2];
  //1,5
  if (num === 1) return map1[0];
  if (num === 5) return map1[1];
  //4,9
  if (num == 4) return map1[0] + map1[1];
  if (num == 9) return map1[0] + map2[0];
  // 2,3
  if (num <= 3) return map1[0].repeat(num);
  // 6, 7, 8
  if (num > 5) return map1[1] + fn1(num - 5);
}

10-99实现(只需要考虑10,90这种即可)

// [10, 99]
function fn2(num) {
  const map2 = mapping[2];
  const map3 = mapping[3];
  if (num === 10) return map2[0];
  if (num === 50) return map2[1];

  //4,9
  if (num == 40) return map2[0] + map2[1];
  if (num == 90) return map2[0] + map3[0];

  // 2,3
  if (num <= 30) return map2[0].repeat(num / 10);
  // 60, 70, 80
  if (num > 50) return map2[1] + fn2(num - 50);
}

思考一下78的实现

// 78
console.log(fn2(70) + fn1(8));

重构 fn1/fn2,反思 fn3/fn4的实现

var mapping = {
  0: ["I", "V"],
  1: ["X", "L"],
  2: ["C", "D"],
  3: ["M", "Z"],
};

// [1-9]
// I II III IV V VI VII VIII IX
function fn(num, e) {
  const map1 = mapping[0 + e];
  const map2 = mapping[1 + e];
  const plus = Math.pow(10, e);
  //1,5
  if (num === 1 * plus) return map1[0];
  if (num === 5 * plus) return map1[1];
  //4,9
  if (num == 4 * plus) return map1[0] + map1[1];
  if (num == 9 * plus) return map1[0] + map2[0];
  // 2,3
  if (num <= 3 * plus) return map1[0].repeat(num / (1 * plus));
  // 6, 7, 8
  if (num > 5 * plus) return map1[1] + fn(num - 5 * plus, e);
}

写一个实例

const fn1 = function (num) {
  return fn(num, 0);
};

const fn2 = function (num) {
  return fn(num, 1);
};

const fn3 = function (num) {
  return fn(num, 2);
};

const fn4 = function (num) {
  return fn(num, 3);
};

const res = fn4(1000) + fn3(900) + fn2(90) + fn1(4);
console.log(res); // MCMXCIV

数字分割部分

import ds from '@jswork/digits-split';

ds(1994); 
// [1000, 900, 90, 4];

参考

https://leetcode-cn.com/problems/integer-to-roman/