feat: leetcode 45,55,121,134,135,238,274,380

This commit is contained in:
LouisFonda 2025-03-26 23:03:16 +08:00
parent dfe0072916
commit e24153d3db
Signed by: yigencong
GPG Key ID: 29CE877CED00E966
8 changed files with 292 additions and 0 deletions

View File

@ -0,0 +1,25 @@
/**
* https://leetcode.cn/problems/jump-game/?envType=study-plan-v2&envId=top-interview-150
* @param {number[]} nums
* @return {boolean}
*/
const canJump = function (nums) {
};
/*
贪心算法每一次计数自己能走的最长距离如果在某一个位置上计算出自己的最长距离超过了数组的最大下标则表明可以跳跃整个数组
如果遍历完数组还是没有找到则表明不能跳跃数组
*/
function f1(nums) {
let farthest = 0; // 默认能走到的最远下标初始的时候能走到数组的第一个下表0
for (let i = 0; i < nums.length; i++) {
// 如果能走的最远距离连当前下表都无法走到直接放回false
if (farthest < i) return false;
// 如果能走到当前下标就比较farthest 和 当前下表加上此时的值谁大更新farthest
farthest = Math.max(farthest, i + nums[i]);
// 如果更新后的farthest 超过了数组的最大下表就表示数组能跳跃整个数组直接返回true
if (farthest >= (nums.length - 1)) return true;
}
return false;
}

View File

@ -0,0 +1,36 @@
/**
* https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/?envType=study-plan-v2&envId=top-interview-150
* @param {number[]} prices
* @return {number}
* 暴力解法遍历整个数组找到买入点和所有卖出点的利润如果利润大于当前利润就更新最大利润最后返回最大利润,会超时
*/
function f1(prices) {
let maxProfit = 0;
const size = prices.length;
for (let i = 0; i < size; i++) {
for (let j = i + 1; j < size; j++) {
if (prices[j] - prices[i] > maxProfit) maxProfit = prices[j] - prices[i];
}
}
return maxProfit;
}
/**
* @param {number[]} prices
* @return {number}
*单次遍历法定义两个变量一个maxProfit = 0一个minPrice=InfinitymaxProfit和上面的暴力法是一样的保存最大利润maxProfit
*表示的是买入的最小价格买入的越小后面如果遇到大于它的价格利润就越大如果利润比maxProfit还大就可以更新maxProfit了最后
*返回即可
*/
function f2(prices) {
let maxProfit = 0;
let minPrice = Infinity;
for (let i = 0; i < prices.length; i++) {
if (prices[i] < minPrice) {
minPrice = prices[i];
} else if (prices[i] - minPrice > maxProfit) { maxProfit = prices[i] - minPrice; }
}
return maxProfit;
}

View File

@ -0,0 +1,28 @@
/**
* https://leetcode.cn/problems/gas-station/?envType=study-plan-v2&envId=top-interview-150
* @param {number[]} gas
* @param {number[]} cost
* @return {number}
*/
const canCompleteCircuit = function (gas, cost) {
let totalGas = 0; let
totalCost = 0;
let currentGas = 0;
let start = 0;
for (let i = 0; i < gas.length; i++) {
totalGas += gas[i];
totalCost += cost[i];
currentGas += gas[i] - cost[i];
// 如果油量不足,更新起点为下一个加油站
if (currentGas < 0) {
start = i + 1;
currentGas = 0;
}
}
// 如果总油量小于总油耗,无法完成一圈
return totalGas < totalCost ? -1 : start;
};

View File

@ -0,0 +1,43 @@
/**
* https://leetcode.cn/problems/candy/?envType=study-plan-v2&envId=top-interview-150
* @param {number[]} ratings
* @return {number}
*/
const candy = function (ratings) {
};
/*
贪心算法每个孩子至少分一颗糖果所以一开始就初始化糖果数组所有元素为1假设我们是中间的那个孩子如果我评分比左边的孩子高
我应该就要比他多获得一个糖果如果我们比右边的孩子评分高我们就应该比右边的孩子多一个糖果但是我们在处理时先从左往右处理
也就是如果当前孩子比左边孩子评分高就在之前的孩子基础上加上1这样处理之后会发生一个问题就是前面的孩子在评分比后面孩子高的时候
它获得的糖果已经比后面的孩子多了所以在处理右边孩子的时候需要比较当前值和后面孩子糖果加一谁大取大的那个值说起来挺难理解
自己用三个孩子思考一下还是很好理解的
*/
function f1(ratings) {
const n = ratings.length;
// 初始化糖果数组
const candies = new Array(n).fill(1);
// 从左往右处理孩子如果当前孩子的评分比之前孩子高当前孩子的糖果数改为之前孩子的糖果数加1
for (let i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
candies[i] = candies[i - 1] + 1;
}
}
// 从右往左遍历如果当前孩子的评分高就必须保证当前孩子的糖果数比后面孩子的糖果数加1大但是经过从左往右的处理
// 当前孩子在评分高的情况下糖果数已经大于右边孩子,这样就已经满足要求了,就不要处理了
for (let i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
candies[i] = Math.max(candies[i], candies[i + 1] + 1);
}
}
// 返回总糖果数
// return candies.reduce((total, cur) => total + cur, 0);
let total = 0;
for (let i = 0; i < n; i++) {
total += candies[i];
}
return total;
}

View File

@ -0,0 +1,25 @@
/**
* https://leetcode.cn/problems/product-of-array-except-self/?envType=study-plan-v2&envId=top-interview-150
* @param {number[]} nums
* @return {number[]}
*/
const productExceptSelf = function (nums) {
const n = nums.length;
const result = new Array(n).fill(1);
// 计算每个位置左侧的乘积
let leftProduct = 1;
for (let i = 0; i < n; i++) {
result[i] = leftProduct;
leftProduct *= nums[i];
}
// 计算每个位置右侧的乘积并与左侧乘积相乘
let rightProduct = 1;
for (let i = n - 1; i >= 0; i--) {
result[i] *= rightProduct;
rightProduct *= nums[i];
}
return result;
};

View File

@ -0,0 +1,31 @@
/**
* https://leetcode.cn/problems/h-index/?envType=study-plan-v2&envId=top-interview-150
* @param {number[]} citations
* @return {number}
*/
const hIndex = function (citations) {
};
/*
思路利用贪心算法遍历整个数组假设默认是h0,表示有至少零篇论文被引用了至少零次[0][0,0] 这些都满足我们遍历的时候检查有没有
符合h+1的论文如果有的化就h++说明h指数应该增加了否则的话就表示这个人的学术水平就是当前h没有必要找下面的h了直接break
*/
function f1(citations) {
const n = citations.length; // 论文的数量
citations.sort((a, b) => b - a); // 按引用次数降序排序
let h = 0; // h指数
// 遍历排序后的数组,寻找最大符合条件的 h 指数
for (let i = 0; i < n; i++) {
if (citations[i] >= h + 1) { // 如果当前论文引用次数大于等于 h+1
h++; // 更新 h 指数
} else {
break; // 如果不满足条件,则退出循环
}
}
return h;
}
console.log(f1([1, 3, 1]));

View File

@ -0,0 +1,50 @@
// O(1) 时间插入、删除和获取随机元素
// 学习目标,利用哈希表和动态数组实现高效数据结构
const RandomizedSet = function () {
this.nums = [];// 动态数组储存真实数据目的是实现O(1)时间内返回随机数据
this.valToIndex = new Map(); // 哈希表实现O(1)时间内查找,删除,插入
};
/**
* @param {number} val
* @return {boolean}
*/
RandomizedSet.prototype.insert = function (val) {
// 先判断插入的数据是否已经存在如果存在直接返回false
if (this.valToIndex.has(val)) return false;
// 维护插入数据的下标
this.valToIndex.set(val, this.nums.length);
this.nums.push(val);
return true;
};
/**
* @param {number} val
* @return {boolean}
*/
RandomizedSet.prototype.remove = function (val) {
// 先判断元素是否存在如果不存在就返回false
if (!this.valToIndex.has(val)) return false;
// 获取当前元素和最后一个元素的下标
const index = this.valToIndex.get(val);
const lastVal = this.nums[this.nums.length - 1];
// 把最后一个元素覆盖到当前位置
this.nums[index] = lastVal;
// 更新原本最后一个元素在哈希表中维持的位置
this.valToIndex.set(lastVal, index);
// 删除最后一个位置的数据
this.nums.pop();
// 删除当前元素在哈希表中维持的位置
this.valToIndex.delete(val);
return true;
};
/**
* @return {number}
*/
RandomizedSet.prototype.getRandom = function () {
// 引入动态数组的目的就是为了实现O(1)返回随机数据
const randomIndex = Math.floor(Math.random() * this.nums.length);
return this.nums[randomIndex];
};

View File

@ -0,0 +1,54 @@
/**
* https://leetcode.cn/problems/jump-game-ii/?envType=study-plan-v2&envId=top-interview-150
* @param {number[]} nums
* @return {number}
*/
const jump = function (nums) {
};
/*
贪心算法从后往前找能到达最后一个位置则表明符合要求所以找能到达最后一个位置的所有下标最小的那个找到这个位置之后继续找能
到达倒数第二个位置的最远的那个位置直到发现第0个下标也符合即可
*/
function f1(nums) {
let position = nums.length - 1; // 表示需要到达的位置,初始时是数组的最后一个位置
let steps = 0; // 记录需要跳跃的步数
while (position > 0) {
for (let i = 0; i < position; i++) {
// 从左往右遍历能到达position的位置如果找到那么这个位置就是我们要找的
if (nums[i] + i >= position) {
// 更新position
position = i;
steps++;
break;
}
}
}
return steps;
}
/**
* 贪心算法
*
*/
function f2(nums) {
// 第一步能到达的最远位置
let maxPos = 0;
let end = 0;
let steps = 0;
// 无需遍历到最后一个元素,最后一个元素一定能被之前的某个位置跳到
for (let i = 0; i < nums.length - 1; i++) {
if (maxPos >= i) { // 更新能跳跃的最远位置
maxPos = Math.max(maxPos, i + nums[i]);
// 如果当前位置已经到达能走的最远位置,则更新下一步的边界
if (end === i) {
end = maxPos;
steps++;
}
}
}
return steps;
}