diff --git a/top-interview-leetcode150/numbers-and-strings/13罗马数字转整数.js b/top-interview-leetcode150/numbers-and-strings/13罗马数字转整数.js new file mode 100644 index 0000000..97526a9 --- /dev/null +++ b/top-interview-leetcode150/numbers-and-strings/13罗马数字转整数.js @@ -0,0 +1,82 @@ +/** + * 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; +} diff --git a/top-interview-leetcode150/numbers-and-strings/42接雨水.js b/top-interview-leetcode150/numbers-and-strings/42接雨水.js new file mode 100644 index 0000000..060b632 --- /dev/null +++ b/top-interview-leetcode150/numbers-and-strings/42接雨水.js @@ -0,0 +1,84 @@ +/** + * https://leetcode.cn/problems/trapping-rain-water/?envType=study-plan-v2&envId=top-interview-150 + * @param {number[]} height + * @return {number} + */ +const trap = function (height) { + +}; + +/* + 观察可以发现:我们只需要把每个位置上的水量加起来,就是总水量了,每个位置上的水量取决于它左右两侧最高柱子较低的那个柱子减去 + 自身的高度,所以我们只需要定义两个数组leftMax和rightMax 来保存当前柱子左边和右边的最高柱子,之后再统计所有水量 + */ + +function f1(height) { + // 如果数组为空或者长度小于3,无法接水,直接返回0 + if (height.length < 3) return 0; + + const n = height.length; + // 创建两个数组,分别存储左边和右边的最大高度 + const leftMax = new Array(n); + const rightMax = new Array(n); + + // 初始化左边最大高度数组 + // leftMax[0] = height[0]; + [leftMax[0]] = height; + for (let i = 1; i < n; i++) { + leftMax[i] = Math.max(leftMax[i - 1], height[i]); + } + + // 初始化右边最大高度数组 + rightMax[n - 1] = height[n - 1]; + for (let i = n - 2; i >= 0; i--) { + rightMax[i] = Math.max(rightMax[i + 1], height[i]); + } + + let water = 0; + + // 计算每个位置能够接的水量 + for (let i = 0; i < n; i++) { + // 能接的水量 = 该位置的左边最大高度与右边最大高度中的较小值减去该位置的高度 + water += Math.min(leftMax[i], rightMax[i]) - height[i]; + } + + return water; +} + +/* +方法2,一个位置要想接住水,它的左右两侧必须比他高,不光左右两侧有多远,只要比他高就一定能接住雨水,但是这个接住的雨水应该是 +多少,应该由谁决定,经过观察也很好发现,其实就是左右两侧较低的那一边,如果一个位置左侧有一个最大的柱子,右侧也有最大的柱子,那么 +它的接水量就是左右两侧较小的那一个减去当前柱子的高度,中间柱子的高度不影响这一位置的接水量(仔细思考这一点) +*/ + +function f2(height) { + let left = 0; let + right = height.length - 1; + let leftMax = 0; let + rightMax = 0; + let water = 0; + + // 双指针向中间靠拢 + while (left < right) { + // 优化:先判断哪个边界较低,频繁出现的情况优先处理 + if (height[left] < height[right]) { + // 左边较低,更新左边的最大高度 + if (height[left] >= leftMax) { + leftMax = height[left]; // 更新左边的最大高度 + } else { + water += leftMax - height[left]; // 计算水量 + } + left++; // 向右移动 + } else { + // 右边较低或相等,更新右边的最大高度 + if (height[right] >= rightMax) { + rightMax = height[right]; // 更新右边的最大高度 + } else { + water += rightMax - height[right]; // 计算水量 + } + right--; // 向左移动 + } + } + + return water; // 返回总的接水量 +}