【经典专题】数字与罗马数字的转换——罗马数字的计数本质

问题引入

你了解罗马数字吗?

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

图源Leetcode官方题解

举几个栗子:

LVIII = L + V +III = 50 + 5 + 3 = 58

MXLIV = M + XL + IV = 1000 + 40 + 4 = 1044

 
 

问题1:数字转罗马数字

解法一:贪心+哈希

对于数字num,使用贪心的思路,剥离下来从大到小的数字。同时我们还要借助一个哈希表。

class Solution {
    public String intToRoman(int num) {
    	// 数字与罗马数字的哈希映射
        Map<Integer, String> map = new HashMap<>();
        map.put(1000, "M");
        map.put(900, "CM");
        map.put(500, "D");
        map.put(400, "CD");
        map.put(100, "C");
        map.put(90, "XC");
        map.put(50, "L");
        map.put(40, "XL");
        map.put(10, "X");
        map.put(9, "IX");
        map.put(5, "V");
        map.put(4, "IV");
        map.put(1, "I");
        // HashMap是无序的,为了保证剥离下来的数字是从大到小的,还需要一个数组
        int[] arr = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};

		// 贪心构建字符串
        StringBuilder sb = new StringBuilder();
        for (int n : arr) {
            while (num / n > 0) {
                sb.append(map.get(n));
                num -= n;
            }
        }
        return sb.toString();
    }
}

解法二:贪心+数组

我们可以对解法一进行改进,不使用哈希表,而是使用数字数组与罗马数字数组,二者通过下标实现一一对应。同时,下标从左到右移动,即可保证数字从大到小。

class Solution {
    public String intToRoman(int num) {
    	// 数字数组
        int[] arr = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
        // 罗马数字数组
        String[] roman = {"M", "CM" , "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};

		// 贪心构建字符串
        StringBuilder sb = new StringBuilder();
        int index = 0;
        while (num != 0) {
            while (num / arr[index] > 0) {
                sb.append(roman[index]);
                num -= arr[index];
            }
            index++;
        }
        return sb.toString();
    }
}

 
 

问题2:罗马数字转数字

解法一:字符串切割

思路很简单,不断切割下来罗马数字字符串,并将对应的数字加到结果上。切割的时候,仍旧是尽量使用“数值大”的字符串进行切割。

class Solution {
    public int romanToInt(String s) {
        int[] arr = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
        String[] roman = {"M", "CM" , "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};

        int num = 0;
        int index = 0;
        while (s.length() > 0) {
            while (s.startsWith(roman[index])) {
                num += arr[index];
                s = s.substring(roman[index].length());
            }
            index++;
        }
        return num;
    }
}

解法二:加减法

以这道题为契机,下面讲一下罗马数字的本质。

罗马数字的单个字符从左到右是递减的,如果出现递增的反常情况,则左侧字符变负数。

看下图很容易理解:

在这里插入图片描述

class Solution {
    public int romanToInt_2(String s) {
        Map<Character, Integer> map = new HashMap<>();
        map.put('M', 1000);
        map.put('D', 500);
        map.put('C', 100);
        map.put('L', 50);
        map.put('X', 10);
        map.put('V', 5);
        map.put('I', 1);

        int num = 0;
        for (int i = 0; i < s.length(); i++) {
        	// 出现递增反常,则用减法;否则用加法
            if (i + 1 < s.length() && map.get(s.charAt(i)) < map.get(s.charAt(i + 1))) {
                num -= map.get(s.charAt(i));
            } else {
                num += map.get(s.charAt(i));
            }
        }
        return num;
    }
}

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

E N D END END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值