【四十八】【算法分析与设计】单调栈,单调栈模板,单调栈求个元素值 最近小于(等于)或者大于(等于)下标,元素值平方 最近小于(等于)下标,元素值左边最近大于等于右边最近大于的下标

本文介绍了如何利用单调栈数据结构解决求解数组中每个元素左右两边最近小于等于的元素下标的算法,涉及两个方法:getNearLessEqual和getNearLess。关键在于维护栈的单调性,确保栈顶元素满足特定条件。

求各个元素左边和右边的最近的小于(等于)的下标

最近的小于的计算过程:

实现的过程需要用到一个stack<==>st

黑盒:在st的元素都可以正确计算出最近小于的元素下标那么我们依次将arr中的元素入栈计即可

1.栈里面存储的是vector,vector存储的是元素的下标,同一个vector存储的这些下标对应的元素值是相同的

⒉栈从栈底到栈顶,vector对应的元素值是严格递增的,因为相同的值下标放到同一个vector里面了

3.当i下标想要入栈,必须保证i下标对应元素值大于等于栈顶vector对应的元素值或者栈空4.如果i下标对应元素值大于等于栈顶vector对应的元素值,直接入栈st.push({i))

5.如果i下标对应元素值小于栈顶vector对应的元素值,此时我们可以直到栈顶vector所有元素的左边最近小于元素下标和右边最近小于元素下标

6.左边最近小于元素下标是在栈顶下面压着的vector的最后一个元素7.右边最近小于元素下标是i

8.依次st.pop维护pop出来的vector里面所有元素最近最小下标,直到i下标对应元素值大于等于栈顶vector对应元素值,或者栈空


#include<bits/stdc++.h>
using namespace std;
class Solution {
public:
        vector<pair<int, int>> getNearLessEqual(vector<int>& arr) {
                vector<pair<int, int>> ret(arr.size());

                stack<int> st;
                for (int i = 0; i < arr.size(); i++) {
                        while (!(st.empty() || arr[i] > arr[st.top()])) {
                                int top = st.top(); st.pop();
                                int leftlessindex = st.empty() ? -1 : st.top();
                                ret[top].first = leftlessindex;
                                ret[top].second = i;
                        }
                        st.push(i);
                }

                while (!st.empty()) {
                        int top = st.top(); st.pop();
                        int leftlessindex = st.empty() ? -1 : st.top();
                        ret[top].first = leftlessindex;
                        ret[top].second = -1;
                }



                return ret;
        }

        vector<pair<int, int>> getNearLess(vector<int>& arr) {
                vector<pair<int, int>> ret(arr.size());

                stack<vector<int>> st;
                for (int i = 0; i < arr.size(); i++) {
                        while (!(st.empty() || arr[i] >= arr[st.top()[0]])) {
                                vector<int> top = st.top(); st.pop();
                                int leftlessindex = st.empty() ? -1 : st.top().back();
                                for (auto x : top) {
                                        ret[x].first = leftlessindex;
                                        ret[x].second = i;
                                }
                        }
                        if (!st.empty() && arr[i] == arr[st.top()[0]]) {
                                st.top().push_back(i);
                        } else {
                                st.push({ i });
                        }
                }

                while (!st.empty()) {
                        vector<int> top = st.top(); st.pop();
                        int leftlessindex = st.empty() ? -1 : st.top().back();
                        for (auto x : top) {
                                ret[x].first = leftlessindex;
                                ret[x].second = -1;
                        }
                }



                return ret;
        }

vector<pair<int, int>> getNearLessEqual_1(vector<int>& arr) {
                vector<pair<int, int>> ret(arr.size());

                stack<vector<int>> st;
                for (int i = 0; i < arr.size(); i++) {
                        while (!(st.empty() || arr[i] > arr[st.top()[0]])) {
                                vector<int> top = st.top(); st.pop();
                                int leftlessindex = st.empty() ? -1 : st.top().back();
                                for (auto x : top) {
                                        ret[x].first = leftlessindex;
                                        ret[x].second = i;
                                }
                        }
                        if (!st.empty() && arr[i] == arr[st.top()[0]]) {
                                st.top().push_back(i);
                        } else {
                                st.push({ i });
                        }
                }

                while (!st.empty()) {
                        vector<int> top = st.top(); st.pop();
                        int leftlessindex = st.empty() ? -1 : st.top().back();
                        for (auto x : top) {
                                ret[x].first = leftlessindex;
                                ret[x].second = -1;
                        }
                }



                return ret;
        }


vector<pair<int, int>> getNearf1(vector<int>& arr) {
                vector<pair<int, int>> ret(arr.size());

                stack<vector<int>> st;
                for (int i = 0; i < arr.size(); i++) {
                        while (!(st.empty() || arr[i]*arr[i] > arr[st.top()[0]]* arr[st.top()[0]])) {
                                vector<int> top = st.top(); st.pop();
                                int leftlessindex = st.empty() ? -1 : st.top().back();
                                for (auto x : top) {
                                        ret[x].first = leftlessindex;
                                        ret[x].second = i;
                                }
                        }
                        if (!st.empty() && arr[i] == arr[st.top()[0]]) {
                                st.top().push_back(i);
                        } else {
                                st.push({ i });
                        }
                }

                while (!st.empty()) {
                        vector<int> top = st.top(); st.pop();
                        int leftlessindex = st.empty() ? -1 : st.top().back();
                        for (auto x : top) {
                                ret[x].first = leftlessindex;
                                ret[x].second = -1;
                        }
                }



                return ret;
        }
};

int main() {
        vector<int> arr = { 3,2,4,3,3,4,1,3,4,5, };
        //                  0 1 2 3 4 5 6 7 8 9
        vector<pair<int, int>> ret = Solution().getNearf1(arr);
        for (int i = 0; i < arr.size(); i++) {
                cout << i << ":" << "[" << ret[i].first << "," << ret[i].second << "]" << endl;
        }
}

求各个元素左边和右边的最近的大于(等于)的下标

只需要保证栈从栈底到栈顶是严格递减即可,其他逻辑是一样的。

单调栈的扩展

单调栈不止求最近值的大小,还可以是其他的性质,只需要满足栈底到栈顶维持这个性质的单调性即可,当加入的元素不能满足这个单调性,此时就可以依次最近的某个性质。

求各个元素左边和右边最近 平方数 小于(等于)的下标


vector<pair<int, int>> getNearf1(vector<int>& arr) {
                vector<pair<int, int>> ret(arr.size());

                stack<vector<int>> st;
                for (int i = 0; i < arr.size(); i++) {
                        while (!(st.empty() || arr[i]*arr[i] > arr[st.top()[0]]* arr[st.top()[0]])) {
                                vector<int> top = st.top(); st.pop();
                                int leftlessindex = st.empty() ? -1 : st.top().back();
                                for (auto x : top) {
                                        ret[x].first = leftlessindex;
                                        ret[x].second = i;
                                }
                        }
                        if (!st.empty() && arr[i] == arr[st.top()[0]]) {
                                st.top().push_back(i);
                        } else {
                                st.push({ i });
                        }
                }

                while (!st.empty()) {
                        vector<int> top = st.top(); st.pop();
                        int leftlessindex = st.empty() ? -1 : st.top().back();
                        for (auto x : top) {
                                ret[x].first = leftlessindex;
                                ret[x].second = -1;
                        }
                }



                return ret;
        }

求各个求各个元素左边最近大于等于右边最近大于的下标



class Solution {
public:
    int getNeat_LeftHightEqual_RightHight(vector<int>& h) {
        int n = h.size();
        vector<pair<int, int>> map(n);
        stack<vector<int>> st;

        for (int i = 0; i < n; i++) {
            while (!(st.empty() || h[i] < h[st.top()[0]])) {
                vector<int> top = st.top();
                st.pop();
                int leftminindex = st.empty() ? -1 : st.top().back();
                for (auto x : top) {
                    map[x].first = leftminindex;
                    map[x].second = i;
                }
            }
            st.push({i});
        }
        while (!st.empty()) {
            vector<int> top = st.top();
            st.pop();
            int leftminindex = st.empty() ? -1 : st.top().back();
            for (auto x : top) {
                map[x].first = leftminindex;
                map[x].second = -1;
            }
        }

        return ret;
    }
};

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

妖精七七_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值