Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目
罗马数字包含以下七种字符: 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:
输入: num = 3
输出: "III"
示例 2:
输入: num = 4
输出: "IV"
示例 3:
输入: num = 9
输出: "IX"
示例 4:
输入: num = 58
输出: "LVIII"
解释: L = 50, V = 5, III = 3.
示例 5:
输入: num = 1994
输出: "MCMXCIV"
解释: M = 1000, CM = 900, XC = 90, IV = 4.
提示:
1 <= num <= 3999
二、我的解答
第一次解答:
当我写了这么多行代码的时候 ,我就清楚地知道,我又垃圾了。
class Solution {
public static String intToRoman(int num) {
int m = 0, d = 0, c = 0, l = 0, x = 0, v = 0, i = 0;
int cm = 0;//cm 900
int cd = 0;//CD
int xc = 0;//XC 90
int xl = 0;//XL
int ix = 0;//IX 9
int iv = 0;//IV
m = num / 1000;
int left = num - m * 1000;
if (left / 900 > 0) {
cm = left / 900;
left = left - 900 * cm;
} else {
d = left / 500;
left = left - 500 * d;
}
if (left / 400 > 0) {
cd = left / 400;
left = left - 400 * cd;
} else {
cd = left / 100;
left = left - 100 * cd;
}
if (left / 90 > 0) {
xc = left / 90;
left = left - 90 * xc;
} else {
l = left / 50;
left = left - 50 * cd;
}
if (left / 40 > 0) {
xl = left / 40;
left = left - 40 * xl;
} else {
l = left / 10;
left = left - 10 * cd;
}
if (left / 9 > 0) {
ix = left / 9;
left = left - 9 * ix;
} else {
l = left / 5;
left = left - 5 * cd;
}
if (left / 4 > 0) {
iv = left / 4;
} else {
l = left;
}
String[] display = new String[]{"M", "CM", "CD", "D", "C", "XC", "XL", "L", "X", "V", "IX", "IV", "I"};
int[] values = new int[]{m, cm, cd, d, c, xc, xl, l, x, v, ix, iv, i};
String result = "";
for (int i1 = 0; i1 < values.length; i1++) {
for (int i2 = 0; i2 < values[i1]; i2++) {
result=result+display[i1];
}
}
return result;
}
}
报错:解答错误
最后执行的输入:3
第二次解答:
class Solution {
public static String intToRoman(int num) {
int m = 0, d = 0, c = 0, l = 0, x = 0, v = 0, i = 0;
int cm = 0;//cm 900
int cd = 0;//CD
int xc = 0;//XC 90
int xl = 0;//XL
int ix = 0;//IX 9
int iv = 0;//IV
m = num / 1000;
int left = num - m * 1000;
if (left / 900 > 0) {
cm = left / 900;
left = left - 900 * cm;
} else {
d = left / 500;
left = left - 500 * d;
}
if (left / 400 > 0) {
cd = left / 400;
left = left - 400 * cd;
} else {
c = left / 100;
left = left - 100 * c;
}
if (left / 90 > 0) {
xc = left / 90;
left = left - 90 * xc;
} else {
l = left / 50;
left = left - 50 * l;
}
if (left / 40 > 0) {
xl = left / 40;
left = left - 40 * xl;
} else {
x = left / 10;
left = left - 10 * x;
}
if (left / 9 > 0) {
ix = left / 9;
left = left - 9 * ix;
} else {
v = left / 5;
left = left - 5 * v;
}
if (left / 4 > 0) {
iv = left / 4;
} else {
i = left;
}
String[] display = new String[]{"M", "CM", "CD", "D", "C", "XC", "XL", "L", "X", "V", "IX", "IV", "I"};
int[] values = new int[]{m, cm, cd, d, c, xc, xl, l, x, v, ix, iv, i};
String result = "";
for (int i1 = 0; i1 < values.length; i1++) {
for (int i2 = 0; i2 < values[i1]; i2++) {
result=result+display[i1];
}
}
return result;
}
}
三、系统解答
算法的重要性就是避免写出我那么臃肿的代码吧。什么ifelse无穷嵌套,双for循环甚至三层循环无限进入。进阶吧菜鸟!
方法一:模拟
根据罗马数字的唯一表示法,为了表示一个给定的整数num,我们寻找不超过num 的最大符号值,将num 减去该符号值,然后继续寻找不超过num 的最大符号值,将该符号拼接在上一个找到的符号之后,循环直至num 为0。最后得到的字符串即为num 的罗马数字表示。
编程时,可以建立一个数值-符号对的列表valueSymbols,按数值从大到小排列。遍历
valueSymbols 中的每个数值-符号对,若当前数值value 不超过num,则从num 中不断减去value,直至num 小于value,然后遍历下一个数值-符号对。若遍历中num 为0 则跳出循环。
代码
class Solution {
int[] values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
String[] symbols = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
public String intToRoman(int num) {
StringBuffer roman = new StringBuffer();
for (int i = 0; i < values.length; ++i) {
int value = values[i];
String symbol = symbols[i];
while (num >= value) {
num -= value;
roman.append(symbol);
}
if (num == 0) {
break;
}
}
return roman.toString();
}
}
复杂度分析
-
时间复杂度:O(1)。由于valueSymbols 长度是固定的,且这13 字符中的每个字符的出现次数均不会超过3,因此循环次数有一个确定的上限。对于本题给出的数据范围,循环次数不会超过15 次。
-
空间复杂度:O(1)。
方法二:硬编码数字
class Solution {
String[] thousands = {"", "M", "MM", "MMM"};
String[] hundreds = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
String[] tens = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
String[] ones = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
public String intToRoman(int num) {
StringBuffer roman = new StringBuffer();
roman.append(thousands[num / 1000]);
roman.append(hundreds[num % 1000 / 100]);
roman.append(tens[num % 100 / 10]);
roman.append(ones[num % 10]);
return roman.toString();
}
}
-
时间复杂度:O(1)。计算量与输入数字的大小无关。
-
空间复杂度:O(1)。