【LeetCode每日一练】13. 罗马数字转整数(C语言实现,附详细踩坑记录) 一、 题目描述LeetCode 13. 罗马数字转整数罗马数字包含以下七种字符:IVXLCD和M。表格字符数值I1V5X10L50C100D500M1000特殊规则通常情况下罗马数字中小的数字在大的数字的右边。但也存在特例例如 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。给定一个罗马数字将其转换成整数。二、 解题思路这道题的核心在于如何处理“左减右加”的特殊规则。初步思路遍历字符串遇到对应的字符就加上对应的值。难点突破当遇到I、X、C这三个可能触发“减法”的字符时不能直接加值而是要向后偷看一个字符即判断s[i1]如果后面的字符比它大如I后面是V说明这是一个组合IV 4此时加上组合的值并且让索引i额外加 1跳过后面的字符。如果后面的字符不比它大说明是普通字符直接加上对应的值即可。三、 C语言代码实现以下是我使用switch-case结构编写的完整代码1#include stdio.h 2#include string.h 3 4int romanToInt(char* s) { 5 int length strlen(s) - 1; 6 int i 0; 7 int sum 0; 8 9 for(i 0; i length; i) { 10 switch(s[i]) { 11 case I: 12 // 检查是否触发特殊规则 IV(4) 或 IX(9) 13 if(s[i1] V) { 14 sum 4; 15 i; // 跳过下一个字符 16 } else if(s[i1] X) { 17 sum 9; 18 i; 19 } else { 20 sum 1; 21 } 22 break; 23 24 case V: 25 sum 5; 26 break; 27 28 case X: 29 // 检查是否触发特殊规则 XL(40) 或 XC(90) 30 if(s[i1] L) { 31 sum 40; 32 i; 33 } else if(s[i1] C) { 34 sum 90; 35 i; 36 } else { 37 sum 10; 38 } 39 break; 40 41 case L: 42 sum 50; 43 break; 44 45 case C: 46 // 检查是否触发特殊规则 CD(400) 或 CM(900) 47 if(s[i1] D) { 48 sum 400; 49 i; 50 } else if(s[i1] M) { 51 sum 900; 52 i; 53 } else { 54 sum 100; 55 } 56 break; 57 58 case D: 59 sum 500; 60 break; 61 62 case M: 63 sum 1000; 64 break; // 注意最后一个 case 也要加 break养成好习惯 65 } 66 } 67 return sum; 68}四、 踩坑与避坑记录核心复盘误区 1在“大数”分支里判断“小数”一开始我试图在case V里面去判断if(s[i1] I)来处理IV。为什么错因为遍历是从左到右的当遇到IV时当前字符是I程序会进入case I根本不会进入case V。正确做法永远在“较小的数字”分支中去预判下一个“较大的数字”。即在I中判断V/X在X中判断L/C。误区 2Switch-case 漏写 break在写case M时很容易顺手漏掉break;。虽然在当前逻辑下M是最后一个 case 不会引发严重后果但在 C 语言中漏写break会导致case 穿透Fall-through这是极其危险的编程习惯。进阶思考关于s[i1]的数组越界问题当i指向字符串最后一个字符时s[i1]会访问什么在 C 语言中字符串末尾自带隐藏字符\0。当判断s[i1] V时实际上是\0和V比较结果为false程序会安全地走入else分支加上单字符的值。因此在 LeetCode 的标准测试用例下不会报错。注如果在实际工程中更严谨的做法是加上边界判断if(i length s[i1] V)五、 复杂度分析时间复杂度 O(N)O(N)。其中 NN 是字符串s的长度。我们只需要遍历一遍字符串虽然内部有if判断和i跳过操作但每个字符最多被访问一次。空间复杂度 O(1)O(1)。只使用了几个整型变量sum,i,length没有使用额外的数据结构。六、 总结罗马数字转整数是一道非常经典的字符串遍历条件预判题目状态机的思想当前字符的含义往往取决于它下一个字符是什么。细节决定成败switch-case的break、循环边界的控制都是 C 语言基本功的体现。