逆波兰表达式求值
leetcode链接:leetcode.cn/problems/ev…
向零截断的意思是:
对于小于0的整数,向上取整,比如,-1.15,向零截断是-1;
对于大于0的整数,向下取整,比如,1.15,向零截断是1;
在JS中,不能统一的用Math.floor函数处理,Math.floor(-1.15)结果是-2
应该要能很快想到使用栈来做题,因为有点类似消消乐
本题目思路:
- 遇到数字就入栈
- 遇到运算法,则取出末尾两个数字做运算
- 新结果入栈
- 重复,直到遍历完所有元素
- 最后栈中的元素就是结果
var evalRPN = function(tokens) {
let stack = [];
let size = tokens.length;
for (let i = 0; i < size; i++) {
if (Number.isNaN(Number(tokens[i]))) {
// 非数字的运算符
let result;
let n2 = stack.pop();
let n1 = stack.pop();
switch (tokens[i]) {
case "+":
result = n1 + n2;
break;
case "-":
result = n1 - n2;
break;
case "*":
result = n1 * n2;
break;
case "/":
result = n1 / n2;
if (result < 0) {
result = Math.ceil(result);
} else {
result = Math.floor(result);
}
break;
}
// 新结果入栈
stack.push(result);
} else {
// 数字入栈
stack.push(Number(tokens[i]));
}
}
return stack.pop();
};
滑动窗口最大值
leetcode链接:leetcode.cn/problems/sl…
暴力法的时间复杂度是O(n × k),会超出时间限制,这道题目有难度,一刷先理解思路
需要构造一个单调递减队列,队列出口始终是最大值,每次取出队列出口元素即可
思路:
- 前k个元素入队列,入队列的时候要保证队列元素顺序是递减的,不符合的元素要pop
- 取出当前窗口的最大值
- 遍历剩余元素,每次入队列一个元素的同时队列也要出去一个元素(移动窗口位置),出队列的时候需要判断一下是不是最大值,如果是的则直接移除,不是则不进行任何操作
- 重复2-3步
// 构造单调递减队列
var Myqueue = function() {
this.queue = [];
}
Myqueue.prototype.enqueue = function(value) {
if (this.queue.length) {
let back = this.queue[this.queue.length - 1];
while(back !== undefined && value > back) {
this.queue.pop();
back = this.queue[this.queue.length - 1];
}
this.queue.push(value);
} else {
// 队列为空,直接入栈
this.queue.push(value);
}
}
Myqueue.prototype.dequeue = function(value) {
let peek = this.getMaxValue();
if (peek === value) {
this.queue.shift();
}
}
Myqueue.prototype.getMaxValue = function() {
return this.queue[0];
}
var maxSlidingWindow = function(nums, k) {
let size = nums.length;
let result = [];
let queue = new Myqueue();
// 先将k个元素放入队列中,
let i = 0;
while (i < k) {
queue.enqueue(nums[i]);
i++;
}
// 获取当前队列的最大值
result.push(queue.getMaxValue());
let j = 0;
while (i < size) {
// 移动窗口位置,获取最大值
queue.enqueue(nums[i]);
queue.dequeue(nums[j]);
result.push(queue.getMaxValue());
i++;
j++;
}
return result;
};
前 K 个高频元素
leetcode链接:leetcode.cn/problems/to…
统计出现的频率,一般都是用哈希法的map数据结构
思路:哈希表中的key保存元素,value是该元素出现的频率,根据value对map进行排序,取出前k个元素的key值
JS中有两种方式实现map,一种是对象,另一种是Map数据结构(卡哥讲的小顶堆有点复杂了,JS中需要手写实现堆)
使用对象作为哈希表存储,需要借助数组的排序函数,整体处理起来比较繁琐,不过思路比较清晰
var topKFrequent = function(nums, k) {
let result = [];
let objArray = [];
let map = {};
// 统计元素出现的频率
for (let i = 0; i < nums.length; i++) {
if (map[nums[i]]) {
map[nums[i]]++;
} else {
map[nums[i]] = 1;
}
}
// 以key和value的对象形式存储在数组中
for (let key in map) {
let temp = {
key: key,
value: map[key]
}
objArray.push(temp);
}
// 根据value属性进行排序
objArray.sort((a, b) => b.value - a.value);
// 取出前k个元素的key值
for (let i = 0; i < k; i++) {
result.push(Number(objArray[i].key));
}
return result;
};
也可以使用Map数据结构,学习下entries函数的用法
var topKFrequent = function(nums, k) {
let map = new Map();
for (let num of nums) {
if (map.has(num)) {
map.set(num, map.get(num) + 1);
} else {
map.set(num, 1);
}
}
return [...map.entries()]
.sort((a, b) => b[1] - a[1])
.slice(0, k)
.map(i => i[0]);
};