单调栈

104 阅读2分钟

题目1:每日温度

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指在第 i 天之后,才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。

来源:力扣(LeetCode)链接:leetcode-cn.com/problems/da…

/**
 * @param {number[]} temperatures
 * @return {number[]}
 */
var dailyTemperatures = function(temperatures) {
    let answer=new Array(temperatures.length).fill(0);//初始化数组
    let stack=[];//单调栈
    let tempIndex=Infinity;//初始化栈顶
    for(let i=0;i<temperatures.length;i++){
        if(stack.length===0){//栈空时当前索引直接入栈
            tempIndex=i;
            stack.push(tempIndex);
        }else{
            if(temperatures[tempIndex]>=temperatures[i]){//当前索引对应数组元素小于栈顶对应数组元素,入栈
                tempIndex=i;
                stack.push(tempIndex);
            }else{
                while(temperatures[tempIndex]<temperatures[i]){ //不断抛出小于当前索引对应元素的元素,并将对应的answer数组元素修改为当前索引与被抛出元素索引的差值
                    stack.pop();
                    answer[tempIndex]=i-tempIndex;
                    if(stack.length>0){
                        tempIndex=stack.pop(); 
                        stack.push(tempIndex); 
                    } else{
                        tempIndex=i;
                        stack.push(tempIndex);
                    }             
                }
                if(tempIndex!=i){
                    tempIndex=i;
                    stack.push(tempIndex);  
                }  
            }
        }
        
    }
    return answer;
};

第一次写,写的有点乱,参考小册子后简化了一下:

/**
 * @param {number[]} temperatures
 * @return {number[]}
 */
var dailyTemperatures = function(temperatures) {
     let len=temperatures.length;
    let res=new Array(len).fill(0);//结果数组
    let stack=[];//单调栈,存放索引值
    for(let i=0;i<len;i++){
        while(stack.length &&temperatures[i]>temperatures[stack[stack.length-1]]){//破坏单调递减时,从不断抛出比当前元素小的元素
            let tempIndex=stack.pop();
            res[tempIndex]=i-tempIndex;//并将所抛出的索引在结果数组中对应的元素改为当前元素与索引值的差
        }
        stack.push(i);//栈为空或当前元素小于栈顶元素时入栈
    }
    return res;
};

同类题型:【力扣 42 84】

题目2:滑动窗口的最大值

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回 滑动窗口中的最大值 。

来源:力扣(LeetCode)链接:leetcode-cn.com/problems/sl…

方法1:两层遍历(滑动窗口+找到当前窗口的最大值)

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
//找到当前窗口的最大值
var findMax=function(left,nums,right){
    let max=-Infinity;
    for(let i=left;i<=right;i++){
        if(nums[i]>max) max=nums[i];
    }
    return max;
}
var maxSlidingWindow = function(nums, k) {
    if(nums.length===0) return [];
    let res=[];
    for(let left=0;left<=nums.length-k;left++){//滑动窗口
        let right=left+k-1;
        res.push(findMax(left,nums,right));
    }
    return res;
};

方法2:双向队列

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
var maxSlidingWindow = function(nums, k) {
    let twoWayQueue=[];
    let res=[];
    for(let i=0;i<nums.length;i++){
        //维持单调递减
        while(twoWayQueue.length&&nums[i]>nums[twoWayQueue[twoWayQueue.length-1]]){
            twoWayQueue.pop();
        }
        twoWayQueue.push(i);
        console.log(twoWayQueue);//观察队列变化
        if(i>=k-1){ //i=k-1开始第一个滑动窗口成型,需要返回窗口最大值,即当前队首
            let maxNow=nums[twoWayQueue[0]];
            res.push(maxNow);
            if(maxNow===nums[i-k+1]) twoWayQueue.shift();//如果最值为当前窗口最左端元素,下一个窗口将不存在该元素,故出队列。
        }
    }
    return res;
};