题目一 503. 下一个更大元素 II
给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。
数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 。
思路
- 循环数组,则通过遍历两遍数组模拟循环
- 从栈顶到栈尾单调递增栈,栈里元素是数组的值
- 遇到比栈顶元素大的数时开始操作: 弹出栈顶元素,并且记录result的值,直到遇到大于等于它的元素
- 比栈顶元素小或者等于,则直接入栈
var nextGreaterElements = function(nums) {
const len = nums.length;
const result = new Array(len).fill(-1);
const stack = [0];
for (let i = 1; i < 2 * len; i++) {
const val = nums[i % len];
while (stack.length && nums[stack[stack.length - 1]] < val) {
const top = stack.pop();
result[top % len] = val;
}
stack.push(i % len);
}
return result;
};
题目二 42. 接雨水
给定 n
个非负整数表示每个宽度为 1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
思路
方法1 双指针法 按照列来计算每一列可以接水量,每一列的宽度等于1,高度等于min(左侧最大元素,右侧最大元素) - 改列的高度, 所以每一列容量是 height * 1,这样每一列加起来就是总和。
可以提前求出来每一个位置的左侧高度最大值,和右侧元素最大值,这样减少时间复杂度。
// 双指针法
var trap = function(height) {
const len = height.length;
const lMaxHeight = new Array(len).fill(0);
lMaxHeight[0] = height[0];
const rMaxHeight = new Array(len).fill(0);
rMaxHeight[len - 1] = height[len - 1];
// lMaxHeight[i] = max(height[i], lmaxHeight[i-1])
for (let i = 1; i < len - 1; i++) {
lMaxHeight[i] = Math.max(height[i], lMaxHeight[i-1]);
}
// rMaxHeight[i] = max(height[i], lmaxHeight[i+1])
for (let i = len - 2; i > 0; i--) {
rMaxHeight[i] = Math.max(height[i], rMaxHeight[i+1]);
}
let result = 0;
for (let i = 1; i < len - 1; i++) {
const h = Math.min(lMaxHeight[i], rMaxHeight[i]) - height[i];
if (h > 0) {
result += h;
}
}
return result;
};
方法2 单调栈法
维护单调递增的单调栈,栈里内容是元素下标。第一个元素先入栈。
- 如果遇到比栈顶小的元素,则入栈
- 如果等于栈顶元素,出栈,入栈,替换当前元素
- 如果大于栈顶元素,则需要计算结果,表示遇到凹槽了,可以接水了
- top出栈
- 宽度等于 索引相减-1
- 高度等于 当前元素是凹槽的右边元素,top是凹槽,top的下一个元素是凹槽的左边,所以高度等于 min(左侧,右侧) - height
- 如果结果大于0,则相加。
var trap = function(height) {
const len = height.length;
const stack = [0];
let result = 0;
for (let i = 1; i < len; i++) {
const val = height[i];
while (stack.length && height[stack[stack.length-1]] < val) {
let top = stack[stack.length-1];
const right = val;
stack.pop();
if (stack.length) {
const mid = height[top];
// left是当前栈顶元素
top = stack[stack.length - 1];
const left = height[top];
const h = Math.min(left, right) - mid;
const w = i - top - 1;
result += h * w;
}
}
stack.push(i);
}
return result;
}