前端算法(12)

85 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目

罗马数字包含以下七种字符: I, V, X, LCD 和 M

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

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

输入: num = 3
输出: "III"

解题思路

思路一

我们先枚举出可能出现的罗马数字,并表明每个罗马数字所代表的数值,然后对数组进行循环,从大到小的循环罗马数字,并判断传入的参数是否大于该值,如果大于,则减去这个数字并在结果,最后将罗马数字添加到尾部

var intToRoman = function (num) {
    const valueSymbolArr = [[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']]
    let result = ''
    for(const [item,symbol] of valueSymbolArr){
        while(num>=item){
            result+=symbol
            num-=item
        }
        if(num == 0) break
    }
    return result
};

思路二

我们首先要定义出各数字所对应的罗马数字字典,接着呢根据计算规则,我们可以知道,罗马数字字符串的拼接都是从大到小进行拼接的,就是是从“千到一”(M到I)进行拼接,所以,当我们获取到字典的keys,准备开始进行累加遍历的时候,需要对keys先进行反转,让其从大到小排列,最后开始进行遍历累减,每得到一个值,就退出当前遍历。

var intToRoman = function(num) {
    if (!num) return "";
    const NUMBER_DICT = {
        1: 'I',
        4: 'IV',
        5: 'V',
        9: 'IX',
        10: 'X',
        40: 'XL',
        50: 'L',
        90: 'XC',
        100: 'C',
        400: 'CD',
        500: 'D',
        900: 'CM',
        1000: 'M'
    };
    let lastNum = num;
    let romanStr = '';
    let numbers = Object.keys(NUMBER_DICT);
    numbers = numbers.map(i=>Number(i));
    numbers.reverse();
    while (lastNum > 0) {
        let len = 0;
        while (len < numbers.length) {
            if (lastNum >= numbers[len]) {
                lastNum-=numbers[len];
                romanStr+=NUMBER_DICT[numbers[len]]
                break;
            }
            len++;
        }
    }
    return romanStr;
}

思路三

首先把特殊的值给直接返回,减少一下执行的时间,然后考虑每个位上的值,比如十位、百位、千位,如果都换算成个位数,再匹配对应的罗马数字,最后再替换一下各自对应的字符即可

var intToRoman = function (num) {
    let a = 0, b = 0, c = 0, d = 0;
    let str = ''
    const obj = {
        0: '',
        1: 'I',
        2: 'II',
        3: 'III',
        4: 'IV',
        5: 'V',
        6: 'VI',
        7: 'VII',
        8: 'VIII',
        9: 'IX'
    }
    const quickMap = {
        1: 'I',
        5: 'V',
        10: 'X',
        50: 'L',
        100: 'C',
        500: 'D',
        1000: 'M',
    }
    if (quickMap.hasOwnProperty(num)) {
        return quickMap[num];
    }
    function getPrefix(n, val) {
        return Math.floor(n / val);
    }
    if (num > 1000) {
        a = getPrefix(num, 1000);
        for (let i = 0; i < a; i++) {
            str += 'M'
        }
    }
    if (num > 100) {
        b = getPrefix(num - a * 1000, 100);
        str += obj[b].replaceAll('V', 'D').replaceAll('I', 'C').replaceAll('X', 'M');
    }
    if (num > 10) {
        c = getPrefix(num - a * 1000 - b * 100, 10);
        str += obj[c].replaceAll('V', 'L').replaceAll('X', 'C').replaceAll('I', 'X');
    }
    d = getPrefix(num - a * 1000 - b * 100 - c * 10, 1);
    str += obj[d];
    return str;
};