/** * https://leetcode.cn/problems/roman-to-integer/?envType=study-plan-v2&envId=top-interview-150 * @param {string} s * @return {number} */ const romanToInt = function (s) { }; /* 分析:我们通过观察可以发现,罗马数字从左往右读,遇到相同的就相加,比如 I 表示1,II 表示2,但是有几个特殊情况,比如IV 表示4 IX表示9,但是绝对不会出现IIV表示3,因为3已经可以用III表示,所以只要遇到后一个字符比当前字符大就把当前字符对应的值改成负数,最后 把这些数值加起来就可以了,以MCMXCIV为例,如果从左往右遍历,M比后面的C大,所以当前的值就是1000,C比M小,所以其对应的值是-100,比 X大所以对应的值是1000,X比C小所以对应的值是-10,C比I大所以对应的值是100,I比V小所以对应的值是-1,V后面已经没有值了所以就是5,把它们 加起来,1000 + (-100) + 1000 + (-10) + 100 + (-1) + 5 = 1994 */ const map = new Map([ ['I', 1], ['V', 5], ['X', 10], ['L', 50], ['C', 100], ['D', 500], ['M', 1000], ]); function f1(s) { // 如果字符串长度小于2,直接返回对应的值 if (s.length < 2) return map.get(s); const n = s.length; let sum = 0; for (let i = 0; i < n - 1; i++) { const cur = map.get(s[i]); if (cur < map.get(s[i + 1])) { sum -= cur; // 当前字符小于下一个字符时,减去当前字符的值 } else { sum += cur; // 否则,加上当前字符的值 } } // 直接加上最后一个字符对应的数值 return sum + map.get(s[n - 1]); } /* 先处理成数字数字,之后操作数组会更高效 */ function f2(s) { const nums = Array.prototype.map.call(s, (char) => map.get(char)); const len = nums.length; const lastIndex = len - 1; // 保存 len - 1,避免重复计算 let res = 0; for (let i = 0; i < len; i++) { if (i < lastIndex && nums[i] < nums[i + 1]) { nums[i] = -nums[i]; } res += nums[i]; } return res; } function f3(s) { const len = s.length; const lastIndex = len - 1; // 保存 len - 1,避免重复计算 let res = 0; for (let i = 0; i < len; i++) { const currentVal = map.get(s[i]); const nextVal = (i < lastIndex) ? map.get(s[i + 1]) : 0; if (currentVal < nextVal) { res -= currentVal; // 当前字符小于下一个字符时,减去当前字符的值 } else { res += currentVal; // 否则,加上当前字符的值 } } return res; }