价格跨度

86 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第16天,点击查看活动详情

[901. 股票价格跨度]

leetcode.cn/problems/on…

image-20221021230029501


题目的本质就是:求当前位置的元素与「 上一个更大元素」之间相隔的元素个数, 换种说法就是:假设当前位置的值是price,求左边大于price的第一个数的位置和当前位置的差距

做法1:类的成员是一个vector,用于存放当前的price(当天的价格)

1)先把当天的价格插入到vector, (因为股票价格小于或等于今天价格的最大连续日数,跨度都要++,包含当天)

2)定义一个遍历res,记录跨度, 然后从后往前遍历vector,如果price的值大于当前元素arr[i],res++ 直到找到price左侧第一个比price大的元素就break跳出循环, 或者全部元素都比price小

class StockSpanner {
public:
    //本题是求 当前位置的元素与「 上一个更大元素」之间的元素个数
    //本质是求左边大于price的第一个数的位置和当前price位置的差距
    vector<int> arr;
    StockSpanner() {
    }
    
    int next(int price) {
        arr.push_back(price); 
        int res = 0;//记录跨度
        for(int i = arr.size()-1 ;i>=0;i--) //从后往前遍历
        {
            if(price>=arr[i])   
                res++;
            else    //当前arr[i]是price左侧第一个比price大的值
                break;
        }
        return res;
    }
};

方法2:单调栈!

求「上/下 」一个更 「大/小」 元素 ->使用单调栈

class StockSpanner {
public:
    vector<int> nums;//保存已经添加的元素
    stack<int> st;//单调栈,保存的是下标索引,从栈底往栈顶单调递减
    int index ;//当前位置的索引
    StockSpanner()  :index(-1)
    {}
    
    int next(int price) {
        index++;//price元素对应的下标++
        while(!st.empty() && nums[st.top()]<=price)
        {
            //如果栈顶元素对应的值<=price,不断弹出栈顶元素
            st.pop();
        }
​
        //直到栈顶元素对应的值>price,此时栈顶其对应的下标就是比price的上一个更大的元素
        //price和上一个比它大的元素的下标距离就是res : (st.top(),index]
        //如果栈为空,说明前面的所有元素都是比price小的,距离res就是index+1 (因为下标从0开始)
        int res = st.empty()?index+1:index-st.top();
        //更新单调栈,把当前数加到数组
        st.push(index);
        nums.push_back(price);
        return res;
    }
};

判断什么时候应该用单调递增的栈,什么时候应该用单调递减的栈

  1. 往前走找第一个比自己 大 的元素,用单调递减的栈,也就是出栈的元素要求比自身要大, 也就是st.top() <= price才出栈
  2. 往前走找第一个比自己 小 的元素,用单调递增的栈,也就是出栈的元素要求比自身要小,也就是 st.top() >= price才出栈