feat: 添加算法题目35,234,876,739
This commit is contained in:
parent
614b10bcd0
commit
dbcfc3f91a
@ -22,6 +22,7 @@
|
||||
"no-constant-condition": "off", // 允许while(true)
|
||||
"default-case": "off", // 允许switch不写default
|
||||
"no-fallthrough": "off", // 允许case穿透
|
||||
"prefer-destructuring": ["error", {"object": false, "array": false}],
|
||||
"import/extensions": [
|
||||
"error",
|
||||
"ignorePackages", // 忽略 node_modules 内的包
|
||||
|
36
binary-search/35搜索插入位置.js
Normal file
36
binary-search/35搜索插入位置.js
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} target
|
||||
* @return {number}
|
||||
*/
|
||||
const searchInsert = function (nums, target) {
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
直接使用二分查找,二分查找没什么好说的,但是这个题目中target不一定存在nums中,所以需要设置一个pos遍历来保存,target应该插入的位置,
|
||||
我们只需在target < nums[mid]的时候设置一次就行,初始化pos的index=nums.length
|
||||
*/
|
||||
|
||||
function f2(nums, target) {
|
||||
let pos = nums.length;
|
||||
let left = 0;
|
||||
let right = nums.length - 1;
|
||||
|
||||
// 二分查找知道left>right结束查找
|
||||
while (left <= right) {
|
||||
const mid = Math.floor((left + right) / 2);
|
||||
// 如果target<nums[mid] 则更新pos
|
||||
if (target === nums[mid]) return mid;
|
||||
|
||||
if (target < nums[mid]) {
|
||||
pos = mid;
|
||||
right = mid - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
left = mid + 1;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
@ -84,3 +84,48 @@ function topKbest(nums, k) {
|
||||
// 堆顶即为第 k 大元素
|
||||
return heap[0];
|
||||
}
|
||||
|
||||
/*
|
||||
若题目没有要求动态的维护这个topk,那么可以使用quick-select来实现,O(n)的时间复杂度完成这个题目。
|
||||
思路:题目要求我们找出第k大的数,那么当整个数组排序之后,倒数第k个数不就是我们要求的吗?比如[5,4,3,2,1] k = 2,那么排序后[1,2,3,4,5]中
|
||||
倒数第二个数的下标就是nums.length - k = 5 - 2 = 3 nums[3]恰好就是我们要找的这个数,我们没有必要对整个数组排序,我们只要找到排序后这个
|
||||
数正确的位置即可,知道快速排序的话,我们可以使用partition来确定pivot,pivot在partition之后就已经确认,如果pivot的下标等于倒数第k个位置
|
||||
那么pivot就是排序之后的倒数第k个数,也就是topk
|
||||
*/
|
||||
function f2(nums, k) {
|
||||
return quickSelect(nums, 0, nums.length - 1, nums.length - k);
|
||||
}
|
||||
|
||||
function quickSelect(nums, left, right, n) {
|
||||
const p = partition(nums, left, right);
|
||||
if (p === n) return nums[n];
|
||||
return p < n ? quickSelect(nums, p + 1, right, n) : quickSelect(nums, left, p - 1, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分区函数,返回pivot,pivot 左边的数都不大于,右边的数都不小于它
|
||||
* @param {*} nums 要操作的数组
|
||||
* @param {*} left 开始位置,左边界
|
||||
* @param {*} right 结束位置, 右边界
|
||||
* @returns number 返回的piivot
|
||||
*/
|
||||
function partition(arr, left, right) {
|
||||
const pivot = arr[right];
|
||||
let p = left;
|
||||
for (let i = left; i < right; i++) {
|
||||
if (arr[i] <= pivot) {
|
||||
// [arr[i], arr[p]] = [arr[p], arr[i]];
|
||||
swap(arr, i, p);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
// [arr[p], arr[right]] = [arr[right], arr[p]];
|
||||
swap(arr, p, right);
|
||||
return p;
|
||||
}
|
||||
|
||||
function swap(nums, a, b) {
|
||||
const tmp = nums[a];
|
||||
nums[a] = nums[b];
|
||||
nums[b] = tmp;
|
||||
}
|
||||
|
40
linked-list/234回文链表.js
Normal file
40
linked-list/234回文链表.js
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Definition for singly-linked list.
|
||||
* function ListNode(val, next) {
|
||||
* this.val = (val===undefined ? 0 : val)
|
||||
* this.next = (next===undefined ? null : next)
|
||||
* }
|
||||
*/
|
||||
/**
|
||||
* @param {ListNode} head
|
||||
* @return {boolean}
|
||||
*/
|
||||
const isPalindrome = function (head) {
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
利用栈将链表的值存储起来,然后再从头开始遍历链表,比较每个节点的值和栈顶的值是否相等。
|
||||
利用了回文的定义,正着和倒着应该是一样的。
|
||||
*/
|
||||
function f1(head) {
|
||||
const stack = [];
|
||||
let current = head;
|
||||
|
||||
// 第一步:将所有节点的值压入栈中
|
||||
while (current) {
|
||||
stack.push(current.val);
|
||||
current = current.next;
|
||||
}
|
||||
|
||||
// 第二步:从头开始重新遍历链表,同时与栈顶比较
|
||||
current = head;
|
||||
while (current) {
|
||||
if (current.val !== stack.pop()) {
|
||||
return false;
|
||||
}
|
||||
current = current.next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
32
linked-list/876链表的中间节点.js
Normal file
32
linked-list/876链表的中间节点.js
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Definition for singly-linked list.
|
||||
* function ListNode(val, next) {
|
||||
* this.val = (val===undefined ? 0 : val)
|
||||
* this.next = (next===undefined ? null : next)
|
||||
* }
|
||||
*/
|
||||
/**
|
||||
* @param {ListNode} head
|
||||
* @return {ListNode}
|
||||
*/
|
||||
const middleNode = function (head) {
|
||||
|
||||
};
|
||||
|
||||
function ListNode(val, next) {
|
||||
this.val = (val === undefined ? 0 : val);
|
||||
this.next = (next === undefined ? null : next);
|
||||
}
|
||||
|
||||
/*
|
||||
如果利用快慢指针寻找重点,如果有两个中点返回后面那个,直接利用靠右的判断方法 fast && fast.next
|
||||
*/
|
||||
function f1(head) {
|
||||
let slow = head;
|
||||
let fast = head;
|
||||
while (fast && fast.next) {
|
||||
slow = slow.next;
|
||||
fast = fast.next.next;
|
||||
}
|
||||
return slow;
|
||||
}
|
86
monotonic-stack/739每日温度.js
Normal file
86
monotonic-stack/739每日温度.js
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @param {number[]} temperatures
|
||||
* @return {number[]}
|
||||
*/
|
||||
const dailyTemperatures = function (temperatures) {
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
直接利用单调栈,单调栈中存入的是元素的下标,这样不仅能比较元素,还能通过下标设置结果
|
||||
*/
|
||||
function f1(temperatures) {
|
||||
const res = []; // 收集结果
|
||||
const stack = []; // 单调递减栈,寻找右边第一个比栈顶元素大的元素
|
||||
|
||||
for (let i = 0; i < temperatures.length; i++) {
|
||||
// 如果栈为空或者当前元素小于等于栈顶元素,将这个元素的下标压入栈中
|
||||
if (!stack.length || temperatures[i] <= temperatures[stack[stack.length - 1]]) {
|
||||
stack.push(i);
|
||||
} else {
|
||||
// 依次比较栈顶元素,直到栈为空,或者当前元素小于等于栈顶元素
|
||||
while (stack.length && temperatures[i] > temperatures[stack[stack.length - 1]]) {
|
||||
const cur = stack.pop();
|
||||
res[cur] = i - cur;
|
||||
}
|
||||
// 将当前元素下标压入栈中
|
||||
stack.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果栈中还有元素,将其在result中的对应位置设置从0,表示后面没有元素大于当前位置的元素
|
||||
for (const i of stack) {
|
||||
res[i] = 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
chatgpt 优化之后的写法,思路没有变,去除了if判断,逻辑如下:
|
||||
遍历整个温度,如果单调栈有元素,并且当前元素大于栈顶元素,就一直处理,直到栈中没有元素,或者当前元素小于等于栈顶元素
|
||||
然后将当前元素压入栈中
|
||||
*/
|
||||
|
||||
/**
|
||||
* 计算每一天需要等待多少天才会有更高温度。
|
||||
* 如果后面没有更高的温度,则返回 0。
|
||||
*
|
||||
* @param {number[]} temperatures - 每天的温度数组
|
||||
* @returns {number[]} - 返回一个数组,表示每一天距离下一次更高温度的天数
|
||||
*/
|
||||
function f2(temperatures) {
|
||||
// 初始化结果数组,默认所有值为 0(表示找不到更高温度)
|
||||
const res = new Array(temperatures.length).fill(0);
|
||||
|
||||
// 用来存储下标的单调递减栈(栈顶到栈底的温度依次递减)
|
||||
const stack = [];
|
||||
|
||||
// 遍历温度数组
|
||||
for (let i = 0; i < temperatures.length; i++) {
|
||||
const currentTemp = temperatures[i];
|
||||
|
||||
/**
|
||||
* 当前温度比栈顶下标对应的温度大,说明当前是“更高温度”的一天,
|
||||
* 所以可以开始出栈并记录距离。
|
||||
*
|
||||
* 注意:每个元素最多被 push 和 pop 各一次,所以总体时间复杂度是 O(n)
|
||||
*/
|
||||
while (
|
||||
stack.length > 0
|
||||
&& currentTemp > temperatures[stack[stack.length - 1]]
|
||||
) {
|
||||
// 栈顶元素下标
|
||||
const prevIndex = stack.pop();
|
||||
|
||||
// 当前天(i)就是之前那天(prevIndex)等待的更高温度的那一天
|
||||
res[prevIndex] = i - prevIndex;
|
||||
}
|
||||
|
||||
// 无论如何都要把当前下标压栈,作为之后判断的基准
|
||||
stack.push(i);
|
||||
}
|
||||
|
||||
// 栈中剩下的下标所对应的位置已经默认填 0,不需要再处理
|
||||
return res;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user