feat: leetcode 13,42

This commit is contained in:
LouisFonda 2025-03-27 23:12:40 +08:00
parent e24153d3db
commit 11981edc96
Signed by: yigencong
GPG Key ID: 29CE877CED00E966
2 changed files with 166 additions and 0 deletions

View File

@ -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 表示1II 表示2但是有几个特殊情况比如IV 表示4
IX表示9,但是绝对不会出现IIV表示3因为3已经可以用III表示所以只要遇到后一个字符比当前字符大就把当前字符对应的值改成负数最后
把这些数值加起来就可以了,以MCMXCIV为例如果从左往右遍历M比后面的C大所以当前的值就是1000C比M小所以其对应的值是-100
X大所以对应的值是1000X比C小所以对应的值是-10C比I大所以对应的值是100I比V小所以对应的值是-1V后面已经没有值了所以就是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;
}

View File

@ -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; // 返回总的接水量
}