LeetCode0012-整数转罗马数字

该博客介绍了如何将整数转换为罗马数字,重点讨论了当数字小于更大罗马数字的一半时,应当在大数字左侧放置小数字的特殊情况。文章通过分析和代码实现解释了贪心算法在此问题中的应用。
摘要由CSDN通过智能技术生成

LeetCode0012-整数转罗马数字

题目:

罗马数字包含以下七种字符: I, V, X, L,C,D 和 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。

给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。

示例 1:
输入: 3
输出: "III"
示例 2:
输入: 4
输出: "IV"
示例 3:
输入: 9
输出: "IX"
示例 4:
输入: 58
输出: "LVIII"
解释: L = 50, V = 5, III = 3.
示例 5:
输入: 1994
输出: "MCMXCIV"
解释: M = 1000, CM = 900, XC = 90, IV = 4.
分析:

将给定的整数转换为罗马数字需要找到13个符号的序列,这些符号的对应值加起来就是整数。根据符号值,此序列必须按从大到小的顺序排列。符号值如下:
{ M − 1000 C M − 900 D → 500 C D → 400 C → 100 X C → 90 L → 50 X L ⟶ 40 X → 10 I X ⟶ 9 V → 5 I V ⟶ 4 I ⟶ 1 \left\{\begin{array}{ll} \mathbf{M}-1000 & \mathrm{CM}-900 \\ \mathrm{D} \rightarrow 500 & \mathrm{CD} \rightarrow 400 \\ \mathrm{C} \rightarrow 100 & \mathrm{XC} \rightarrow 90 \\ \mathrm{L} \rightarrow 50 & \mathrm{XL} \longrightarrow 40 \\ \mathrm{X} \rightarrow 10 & \mathrm{IX} \longrightarrow 9 \\ \mathrm{V} \rightarrow 5 & \mathrm{IV} \longrightarrow 4 \\ \mathrm{I} \longrightarrow 1 & \end{array}\right. M1000D500C100L50X10V5I1CM900CD400XC90XL40IX9IV4

表示应该使用尽可能大的符号,从左侧开始工作。因此,使用贪心算法是有意义的。贪心算法是一种在当前时间做出最佳可能决策的算法,在这种情况下,它会取出最大可能的符号。
为了表示一个给定的整数,寻找合适它的最大符号。我们减去它,然后寻找适合余数 最大符号,依次类推,直到余数为0,取出的每个符号都附加到输出的罗马数字字符串上。

代码:
/**
 * 0012 整数转罗马数字
 * 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
 * <p>
 * 字符          数值
 * I             1
 * V             5
 * X             10
 * L             50
 * C             100
 * D             500
 * M             1000
 * <p>
 * 例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。
 * <p>
 * 通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。
 * 数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。
 * 同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
 * <p>
 * I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
 * X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
 * C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
 * <p>
 * 给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
 * <p>
 * 示例 1:
 * <p>
 * 输入: 3
 * 输出: "III"
 * <p>
 * 示例 2:
 * <p>
 * 输入: 4
 * 输出: "IV"
 * <p>
 * 示例 3:
 * <p>
 * 输入: 9
 * 输出: "IX"
 * <p>
 * 示例 4:
 * <p>
 * 输入: 58
 * 输出: "LVIII"
 * 解释: L = 50, V = 5, III = 3.
 * <p>
 * 示例 5:
 * <p>
 * 输入: 1994
 * 输出: "MCMXCIV"
 * 解释: M = 1000, CM = 900, XC = 90, IV = 4.
 */

/**
 * 贪心算法
 */
class Solution {
    public String intToRoman(int num) {
        // 把阿拉伯数字与罗马数字可能出现的所有情况和对应关系,放在两个数组中
        // 并且按照阿拉伯数字的大小降序排列,这是贪心选择思想
        int[] nums = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
        String[] romans = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
        // 构建结果集字符串
        StringBuilder stringBuilder = new StringBuilder();
        // 索引,遍历13种组合值
        int index = 0;
        while (index < 13) {
//            特别注意:这里是等号
//            while (num >= nums[index]) { // 这里使用循环,是同一种组合值,可能出现多次
//                // 注意:这里是等于号,表示尽量使用大的"面值"
//                // 找到符合要求的组合值,将其添加进字符串,并让源数字减少对应的值
//                stringBuilder.append(romans[index]);
//                num -= nums[index];
//            }
            /***
             * 与注释二选一即可,通过俩种不同的思路去考虑,注释为通过多次匹配同一个符号值
             * 下面的是通过直接取余,一次考虑,能匹配当前符号值的次数
             */
            // 当前符号值能匹配的最大次数
            int n = num / nums[index];
            if (n > 0) {
                for (int i = 0; i < n; i++) {
                    stringBuilder.append(romans[index]);
                }
            }
            // 去除当前符号值的多次匹配结果
            num %= nums[index];
            index++;
        }
        return stringBuilder.toString();
    }
}

/**
 * 测试类
 */
public class Study0012 {
    public static void main(String[] args) {
        System.out.println(new Solution().intToRoman(1994));
    }
}

结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值