13. 罗马数字转整数

思路

先把字符串转成数组,再遍历转换成数字累加,这样先成功转换成数字

  1. var romanToInt = function (s) {
  2. const rome = {
  3. I: 1,
  4. V: 5,
  5. X: 10,
  6. L: 50,
  7. C: 100,
  8. D: 500,
  9. M: 1000
  10. }
  11. let arr = s.split('');
  12. let res = 0;
  13. for (let i = 0; i < arr.length; i++) {
  14. res += rome[arr[i]]
  15. }
  16. return res
  17. };
  18. }

特殊条件

罗马数字有这六种特殊条件

  1. I 可以放在 V (5) X (10) 的左边,来表示 4 9
  2. X 可以放在 L (50) C (100) 的左边,来表示 40 90
  3. C 可以放在 D (500) M (1000) 的左边,来表示 400 900

在出现 I,X,C时,对比下一个值满不满足对应条件
满足则让后面这个数-前面这个数

比如 出现I时,看一下后面那个数是不是V,是的话就V-I,表示 5-1 = 4

因为当前数的索引数是i,后面那个数的索引是i+1,i++ 表示后面这个数用过了,不需要再判断,跳过下次循环

  1. if (arr[i] === 'I') {
  2. if (arr[i + 1] === 'V' || arr[i + 1] === 'X') {
  3. res += rome[arr[i + 1]] - rome[arr[i]]
  4. i++
  5. }else{
  6. res += rome[arr[i]]
  7. }
  8. }

上述代码重复3遍可得最终通过代码

  1. var romanToInt = function (s) {
  2. const rome = {
  3. I: 1,
  4. V: 5,
  5. X: 10,
  6. L: 50,
  7. C: 100,
  8. D: 500,
  9. M: 1000
  10. }
  11. let arr = s.split('');
  12. let res = 0;
  13. for (let i = 0; i < arr.length; i++) {
  14. if (arr[i] === 'I') {
  15. if (arr[i + 1] === 'V' || arr[i + 1] === 'X') {
  16. res += rome[arr[i + 1]] - rome[arr[i]]
  17. i++
  18. }else{
  19. res += rome[arr[i]]
  20. }
  21. } else if (arr[i] === 'X') {
  22. if (arr[i + 1] === 'L' || arr[i + 1] === 'C') {
  23. res += rome[arr[i + 1]] - rome[arr[i]]
  24. i++
  25. }else{
  26. res += rome[arr[i]]
  27. }
  28. } else if (arr[i] === 'C') {
  29. if (arr[i + 1] === 'D' || arr[i + 1] === 'M') {
  30. res += rome[arr[i + 1]] - rome[arr[i]]
  31. i++
  32. }else{
  33. res += rome[arr[i]]
  34. }
  35. } else {
  36. res += rome[arr[i]]
  37. }
  38. }
  39. return res
  40. };

优化

字符串只有一个罗马字符时,我们可以不用执行循环;字符串有多个字符时,最后一个字就不用判断了,直接取出,所以把条件变一下, 这样能省下一次循环.

  1. for (let i = 0; i + 1 < arr.length; i++){}

未优化的代码判断特殊值时,会去取下一个值看满不满足条件,但标准的罗马数字,一般都是从大到小的顺序表示数字

比如表示6时, 是VI,等于5+1

而不是用IVII 4+1+1表示

所以如果下一位罗马数字大于当前的数字,就能判定是特殊情况

  1. for (let i = 0; i + 1 < arr.length; i++){
  2. if(rome[arr[i]] < rome[arr[i+1]]){
  3. //是特殊情况
  4. }else{
  5. //不是特殊情况
  6. }
  7. }

下面是优化过的代码

  1. var romanToInt2 = function (s) {
  2. const rome = {
  3. I: 1,
  4. V: 5,
  5. X: 10,
  6. L: 50,
  7. C: 100,
  8. D: 500,
  9. M: 1000
  10. }
  11. let pre = rome[s[0]];
  12. let res = 0;
  13. /*
  14. 提示: 'XIV' = X+(V-I) = 10+(5-1) = 10+5+(-1) 10+(-1)+5
  15. 加法交换律,可以理解为需要减的值能提前减
  16. */
  17. for(var i = 0; i + 1 < s.length; i++){
  18. let next = rome[s[i + 1]];
  19. pre < next ? res -= pre : res += pre
  20. pre = next;
  21. }
  22. res += pre;
  23. return res;
  24. };

解释

假设s = XIV => 10, 1, 5带入函数

pre = rome['XIV'[0]] = 10 开始进入循环

  • 第一次循环:
  1. next = rome['XIV'[i + 1]] = 1
  2. 10 < 1 不成立, 于是走 res = 0 + 10 = 10
  3. pre = 1
  • 第二次循环:
  1. next = rome['XIV'[i + 1]] = 5
  2. 1 < 5 成立, 于是走 res = 10 - 1 = 9
  3. pre = 5
  • i自增2次之后值为2,不满足循环条件,说明pre保留的是最后一个值,最后一个值永远都可以直接加,所以不用判断,出循环后直接相加即可