【八十七】【算法分析与设计】单调栈全新版本,右大于,左小于右小于等于,739. 每日温度,907. 子数组的最小值之和

739. 每日温度(右大于)

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

示例 1:

 
 

输入: temperatures = [73,74,75,71,69,72,76,73] 输出: [1,1,4,2,1,1,0,0]

示例 2:

输入: temperatures = [30,40,50,60] 输出: [1,1,1,0]

示例 3:

输入: temperatures = [30,60,90] 输出: [1,1,0]

提示:

  • 1 <= temperatures.length <= 10(5)

  • 30 <= temperatures[i] <= 100

1.

在这个问题中,给定一个数组,代表连续几天的温度,目标是对于每一天,找出需要等待多少天才能有更高的温度。如果没有更高的温度,就返回0。单调栈在这类问题中特别有用,因为它可以帮助我们有效地处理和查询序列中元素的顺序和大小关系。

2.

利用单调栈维护每一个元素右边最近大于元素下标的信息.

arr数组我们用用下标对应元素值.

p_max数组我们用下标对应信息,每一个元素值都有一个信息.记录右边最近大于元素的下标.

3.

用一个循环维护数组p_max的信息,我需要表示右边的最近的信息,那么右边的所有数都需要进入到单调栈里面.所以我们应该从右往左遍历.

每一次都是入栈的时候维护信息.

 
class Solution {
public:
    vector<int> arr; // 用于存储输入的温度数组
    vector<int> ret; // 用于存储输出结果数组
    int n; // 数组长度
    using p=pair<int,int>; // 定义一个 pair 类型 p,用于存储索引和值对
    vector<int> p_max; // 用于存储每个元素右边第一个大于它的元素索引
    vector<int> st; // 辅助栈,用于单调栈实现

    // 初始化函数
    void init(){
        n=arr.size(); // 获取数组长度
        p_max.assign(n,0); // 初始化 p_max,大小为 n,所有元素初始化为 0
        ret.assign(n,0); // 初始化 ret,大小为 n,所有元素初始化为 0
    }

    // 解决函数
    void solve(){
        // 从后往前遍历每个元素,找到每个元素右边第一个比它大的元素
        for(int i=n-1;i>=0;i--){
            while(1){
                if(st.empty())break; // 如果栈为空,跳出循环
                if(arr[i]<arr[st.back()])break; // 如果当前元素小于栈顶元素,跳出循环
                st.pop_back(); // 弹出栈顶元素
            }
            p_max[i]=st.empty()?0:st.back(); // 记录右边第一个比当前元素大的元素索引
            st.push_back(i); // 将当前元素索引入栈
        }

        // 计算每个元素距离下一个更高温度的天数
        for(int i=0;i<n;i++){
            if(p_max[i]!=0)ret[i]=p_max[i]-i; // 如果存在更高温度,计算天数差
            else ret[i]=0; // 如果不存在更高温度,设置为 0
        }
    }

    // 主函数,处理输入并返回结果
    vector<int> dailyTemperatures(vector<int>& _temperatures) {
        ios::sync_with_stdio(false); // 禁用同步,以提高 I/O 性能
        cin.tie(0); // 解除 cin 和 cout 的绑定
        cout.tie(0); // 解除 cout 的绑定
        arr=_temperatures; // 将输入温度数组赋值给 arr
        init(); // 调用初始化函数
        solve(); // 调用解决函数    
        return ret; // 返回结果数组
    }
};

907. 子数组的最小值之和(左小于,右小于等于)

给定一个整数数组 arr,找到 min(b) 的总和,其中 b 的范围为 arr 的每个(连续)子数组。

由于答案可能很大,因此 返回答案模 10^9 + 7

示例 1:

输入:arr = [3,1,2,4] 输出:17 解释: 子数组为 [3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2,4],[3,1,2,4]。 最小值为 3,1,2,4,1,1,2,1,1,1,和为 17。

示例 2:

输入:arr = [11,81,94,43,3] 输出:444

提示:

  • 1 <= arr.length <= 3 * 10(4)

  • 1 <= arr[i] <= 3 * 10(4)

1.左小于,右小于等于--->完美表示所有的情况.

 
class Solution {
public:
    using LL=long long; // 定义长整型别名 LL
    vector<int> arr; // 用于存储输入的数组
    LL n; // 数组长度
    using p=pair<int,int>; // 定义一个 pair 类型 p,用于存储索引对
    vector<p> p_m; // 用于存储每个元素左边和右边第一个小于它的元素索引
    vector<int> st; // 辅助栈,用于单调栈实现
    LL MOD=1e9+7; // 定义常量 MOD 为 10^9 + 7
    LL ret; // 用于存储结果

    // 初始化函数
    void init(){
        n=arr.size(); // 获取数组长度
        p_m.assign(n,{0,0}); // 初始化 p_m,大小为 n,所有元素初始化为 {0,0}
    }

    // 解决函数
    void solve(){
        // 遍历每个元素,找到每个元素左边第一个小于它的元素
        for(int i=0;i<n;i++){
            while(1){
                if(st.empty())break; // 如果栈为空,跳出循环
                if(arr[i]>arr[st.back()])break; // 如果当前元素大于栈顶元素,跳出循环
                st.pop_back(); // 弹出栈顶元素
            }
            p_m[i].first=st.empty()?-1:st.back(); // 记录左边第一个比当前元素小的元素索引
            st.push_back(i); // 将当前元素索引入栈
        }
        st.clear(); // 清空栈

        // 遍历每个元素,找到每个元素右边第一个小于或等于它的元素
        for(int i=n-1;i>=0;i--){
            while(1){
                if(st.empty())break; // 如果栈为空,跳出循环
                if(arr[i]>=arr[st.back()])break; // 如果当前元素大于或等于栈顶元素,跳出循环
                st.pop_back(); // 弹出栈顶元素
            }
            p_m[i].second=st.empty()?n:st.back(); // 记录右边第一个小于或等于当前元素的元素索引
            st.push_back(i); // 将当前元素索引入栈
        }

        // 计算所有子数组最小值的总和
        for(int i=0;i<n;i++){
            ret=(ret+((i-p_m[i].first)*(p_m[i].second-i)%MOD)*arr[i]%MOD)%MOD; // 计算并累加每个子数组的最小值
        }
    }

    // 主函数,处理输入并返回结果
    int sumSubarrayMins(vector<int>& _arr) {
        ios::sync_with_stdio(0); // 禁用同步,以提高 I/O 性能
        cin.tie(0); // 解除 cin 和 cout 的绑定
        cout.tie(0); // 解除 cout 的绑定
        arr=_arr; // 将输入数组赋值给 arr

        init(); // 调用初始化函数
        solve(); // 调用解决函数
        return ret; // 返回结果
    }
};

结尾

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

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

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

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

妖精七七_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值