s七个不同的符号代表罗马数字,其值如下:
符号 | 值 |
---|---|
I | 1 |
V | 5 |
X | 10 |
L | 50 |
C | 100 |
D | 500 |
M | 1000 |
罗马数字是通过添加从最高到最低的小数位值的转换而形成的。将小数位值转换为罗马数字有以下规则:
- 如果该值不是以 4 或 9 开头,请选择可以从输入中减去的最大值的符号,将该符号附加到结果,减去其值,然后将其余部分转换为罗马数字。
- 如果该值以 4 或 9 开头,使用 减法形式,表示从以下符号中减去一个符号,例如 4 是 5 (
V
) 减 1 (I
):IV
,9 是 10 (X
) 减 1 (I
):IX
。仅使用以下减法形式:4 (IV
),9 (IX
),40 (XL
),90 (XC
),400 (CD
) 和 900 (CM
)。 - 只有 10 的次方(
I
,X
,C
,M
)最多可以连续附加 3 次以代表 10 的倍数。你不能多次附加 5 (V
),50 (L
) 或 500 (D
)。如果需要将符号附加4次,请使用 减法形式。
给定一个整数,将其转换为罗马数字。
示例 1:
输入:num = 3749
输出: "MMMDCCXLIX"
解释:
3000 = MMM 由于 1000 (M) + 1000 (M) + 1000 (M) 700 = DCC 由于 500 (D) + 100 (C) + 100 (C) 40 = XL 由于 50 (L) 减 10 (X) 9 = IX 由于 10 (X) 减 1 (I) 注意:49 不是 50 (L) 减 1 (I) 因为转换是基于小数位
示例 2:
输入:num = 58
输出:"LVIII"
解释:
50 = L 8 = VIII
示例 3:
输入:num = 1994
输出:"MCMXCIV"
解释:
1000 = M 900 = CM 90 = XC 4 = IV 提示:
1 <= num <= 3999
做法1.总结来说就是把题目的限制条件,全部使用if-else进行限制,然后往字符串后端添加相对应的字母即可。这种做法的优点就是节省内存,但是运行时间比较长。时间较短的方法可看做法2。该做法更加容易看懂,初学方法。
class Solution {
public:
string intToRoman(int num) {
string res="";
int temp = num,C_s = 1000;
while(temp){
int temp_res = temp / C_s;
int te = temp_res;
if(temp_res){
if(C_s==1000){
while(temp_res){
res += "M";
temp_res--;
}
}else if(C_s==100){
if(temp_res==9){
res += "CM";
}else if(temp_res==4){
res += "CD";
}else if(temp_res >= 5){
res += "D";
temp_res -= 5;
while(temp_res){
res += "C";
temp_res--;
}
}else if(temp_res){
while(temp_res){
res += "C";
temp_res--;
}
}
}else if(C_s==10){
if(temp_res==9){
res += "XC";
}else if(temp_res==4){
res += "XL";
}else if(temp_res >= 5){
res += "L";
temp_res -= 5;
while(temp_res){
res += "X";
temp_res--;
}
}else if(temp_res){
while(temp_res){
res += "X";
temp_res--;
}
}
}else if(C_s==1){
if(temp_res==9){
res += "IX";
}else if(temp_res==4){
res += "IV";
}else if(temp_res >= 5){
res += "V";
temp_res -= 5;
while(temp_res){
res += "I";
temp_res--;
}
}else if(temp_res){
while(temp_res){
res += "I";
temp_res--;
}
}
}
}
temp -= te * C_s;
C_s /=10;
}
return res;
}
};
做法2.
vector<pair<int, string>>
这里先解释一下上面这行代码:
pair
是 C++ 标准库中的一种模板类,用于存储两个相关联的值。这两个值可以是不同类型。这号符合题目中的键值条件。vector
是 C++ 标准库中的模板类,表示动态数组,可以调整其大小并允许在任意位置快速访问元素。
class Solution {
public:
string intToRoman(int num) {
// 罗马数字及其对应的数值
vector<pair<int, string>> roman = {
{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"}
};
string result;
// 遍历罗马数字表
for (const auto& [value, symbol] : roman) {
while (num >= value) {
result += symbol;
num -= value;
}
}
return result;
}
};
另一个需要注意的就是
for (auto [value, symbol] : roman)
这里直接使用auto也对,但是会出现警告,所以就咨询了一下chatgpt,其给出的原因就是:
-
避免复制:
- 当你遍历一个包含复杂对象(例如
pair<int, string>
)的容器时,如果不使用引用而是直接使用值(auto
),会导致每次迭代都进行一次复制操作。复制复杂对象是昂贵的,尤其是在对象包含动态分配的资源时,例如string
。 - 使用
const auto&
避免了这种复制,直接引用容器中的元素,提高了性能。
- 当你遍历一个包含复杂对象(例如
-
保护数据:
- 使用
const
确保在循环内部不会修改容器中的元素。这不仅增加了代码的安全性,还使意图更加明确:你只读取数据而不修改它。 - 这对于读操作特别有用,因为它防止了意外的修改,增加了代码的可读性和维护性。
- 使用
-
类型推导:
auto
关键字让编译器自动推导变量的类型,减少了代码的冗长和出错的机会。特别是在处理复杂类型(如pair<int, string>
)时,auto
使代码更加简洁。
其中auto
:让编译器推导变量的类型。
这里急着下班了,不解释了,就直接让chatgpt给出对于auto的解释。
auto
是 C++ 中的一种类型推导关键字,它允许编译器根据初始化表达式的类型自动推导变量的类型。这在编写代码时提供了更大的简洁性和灵活性。以下是关于 auto
的详细介绍以及在具体场景中使用 auto
的原因。
auto
的基本用法
-
基本示例:
int x = 10; auto y = x; // y 的类型是 int
-
复杂类型的推导:
vector<pair<int, string>> vec; auto p = make_pair(1, "example"); // p 的类型是 pair<int, string> vec.push_back(p);
-
迭代器类型:
vector<int> vec = {1, 2, 3, 4}; auto it = vec.begin(); // it 的类型是 vector<int>::iterator
使用 auto
的原因
-
简化代码:
vector<pair<int, string>> vec; auto it = vec.begin(); // 避免写成 vector<pair<int, string>>::iterator it = vec.begin();
-
提高可读性:
for (auto it = vec.begin(); it != vec.end(); ++it) { // 使用 auto 使得代码更易读 }
-
避免重复:
vector<int> vec = {1, 2, 3}; auto x = vec[0]; // 不需要再次说明 x 的类型是 int
-
类型一致性:
auto result = some_function(); // result 的类型完全与 some_function() 的返回类型一致