代码随想录-单调栈|ACM模式实践

news2024/11/19 8:36:23

代码随想录感想

​​​​​​739. 每日温度

题目描述:

输入输出示例:

思路和想法:

496. 下一个更大元素 I

题目描述:

输入输出示例:

思路和想法:

503. 下一个更大元素 II

题目描述:

输入输出示例:

思路和想法:

42.接雨水

题目描述:

输入输出示例:

思路和想法:

84. 柱状图中最大的矩形

题目描述:

输入输出示例:

思路和想法:


​​​​​​739. 每日温度

题目描述:

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

输入输出示例:

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

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

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

提示:

  • 1 <= temperatures.length <= 105
  • 30 <= temperatures[i] <= 100

思路和想法:

这一道题目是单调栈的模板题,做这道题目可以很好的理解单调栈。

何时想起用单调栈:通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置。

在使用单调栈的时候首先要明确几点:

  1. 单调栈里存放的元素是什么?这道题目放入数组的索引。
  2. 单调栈里元素是递增,还是递减?不确定可以模拟数据入栈和出栈的过程,就可以明晰。
#include<bits/stdc++.h>

using namespace std;

/*
* 作者:希希雾里
* 739. 每日温度 I
* 讲述自己的一些理解和认知
* */

/*单调栈模板题目
* 时间复杂度:O(n)   空间复杂度:O(n)
* */
vector<int> dailyTemperatures(vector<int>& temperatures) {
    vector<int> result(temperatures.size(),0);
    stack<int> st;

    for (int i = 0; i < temperatures.size(); ++i) {
        while (!st.empty() && temperatures[i] > temperatures[st.top()]){
            int mid = st.top();
            st.pop();
            result[mid] = i - mid;
        }
        st.push(i);
    }
    return result;
}

int main() {
    vector<int> number;
    int num;
    while (cin >> num){
        number.push_back(num);
        if(getchar() == '\n'){
            break;
        }
    }

    //这里输出注意,最后一位要注意单独处理。(经常会出现的问题)
    vector<int> result;
    result = dailyTemperatures(number);
    for (int i = 0; i < result.size() - 1; ++i) {
        cout << result[i] << " ";
    }
    cout << result[result.size() - 1];
    return 0;
}

/* 测试样例,列清楚情况
73 74 75 71 69 72 76 73
1 1 4 2 1 1 0 0

30 40 50 60
1 1 1 0

30 60 90
1 1 0
* */

496. 下一个更大元素 I

题目描述:

nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧第一个 比 x 大的元素。

给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。

对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。

返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素

输入输出示例:

输入:nums1 = [4,1,2], nums2 = [1,3,4,2]. 输出:[-1,3,-1]

输入:nums1 = [2,4], nums2 = [1,2,3,4]. 输出:[3,-1]

提示:

  • 1 <= nums1.length <= nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 104
  • nums1和nums2中所有整数 互不相同
  • nums1 中的所有整数同样出现在 nums2 中

思路和想法:

这道题目相较于上一道模板题的升级的地方在于,需要查找元素。无重复元素,这里可以使用map来实现映射,根据数值快速找到下标,并判断nums2[i]是否在nums1中出现过

#include<bits/stdc++.h>

using namespace std;

/*
* 作者:希希雾里
* 496. 下一个更大元素 I
* 讲述自己的一些理解和认知
* 查找(map) + 单调栈
* 上述思路,跟单调栈的内核很好的契合
* */

/*查找 + 单调栈*/
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
    vector<int> result(nums1.size(), -1);

    stack<int> st;
    //构建映射,数值-下标
    unordered_map<int,int> mp;
    for (int i = 0; i < nums1.size(); ++i) {
        mp[nums1[i]] = i;
    }
    
	//单调栈记录
    for (int i = 0; i < nums2.size(); ++i) {
        while(!st.empty() && nums2[i] > nums2[st.top()]){
            if (mp.count(nums2[st.top()]) > 0){
                int index = mp[nums2[st.top()]];
                result[index] = nums2[i];
            }
            st.pop();
        }
        st.push(i);
    }
    return result;
}

int main() {
    vector<int> number1;
    vector<int> number2;
    int num;
    while (cin >> num){
        number1.push_back(num);
        if(getchar() == '\n'){
            break;
        }
    }
    while (cin >> num){
        number2.push_back(num);
        if(getchar() == '\n'){
            break;
        }
    }

    //这里输出注意,最后一位要注意单独处理。(经常会出现的问题)
    vector<int> result;
    result = nextGreaterElement(number1, number2);
    for (int i = 0; i < result.size() - 1; ++i) {
        cout << result[i] << " ";
    }
    cout << result[result.size() - 1];
    return 0;
}

/* 测试样例,列清楚情况
4 1 2
1 3 4 2
-1 3 -1

2 4
1 2 3 4
3 -1
* */

503. 下一个更大元素 II

题目描述:

给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素

数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 。

输入输出示例:

输入: nums = [1,2,1] 输出: [2,-1,2]

输入: nums = [1,2,3,4,3] 输出: [2,3,4,-1,4]

提示:

  • 1 <= nums.length <= 104
  • -109 <= nums[i] <= 109

思路和想法:

这道题目在每日温度的基础上,进阶要循环数组。

初步想法:直接将两个数组拼接在一起就可以了。这个方法比较直观,但做了一些无用的操作,第一步修改nums数组,而且最后还要把数组resize回去。

其实可以应用取余操作,就可以很好的处理解决。

#include<bits/stdc++.h>

using namespace std;

/*
* 作者:希希雾里
* 503. 下一个更大元素 II
* 讲述自己的一些理解和认知
* 核心:循环数组遍历,每一个元素的下一个更大的元素。
* */

/*单调栈*/
vector<int> nextGreaterElements(vector<int>& nums) {
    stack<int> st;
    vector<int> result(nums.size(), -1);

    for (int i = 0; i < 2 * nums.size(); ++i) {
        while(!st.empty() && nums[i % nums.size()] > nums[st.top()]) {
            result[st.top()] = nums[i % nums.size()];
            st.pop();
        }
        st.push(i % nums.size());
    }
    return result;
}

int main() {
    vector<int> number;
    int num;
    while (cin >> num){
        number.push_back(num);
        if(getchar() == '\n'){
            break;
        }
    }

    //这里输出注意,最后一位要注意单独处理。(经常会出现的问题)
    vector<int> result;
    result = nextGreaterElements(number);
    for (int i = 0; i < result.size() - 1; ++i) {
        cout << result[i] << " ";
    }
    cout << result[result.size() - 1];
    return 0;
}

/* 测试样例,列清楚情况
1 2 1
2 -1 2

1 2 3 4 3
2 3 4 -1 4
* */

42.接雨水

题目描述:

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

输入输出示例:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6

解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

输入:height = [4,2,0,3,2,5] 输出:9

提示:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

思路和想法:

这道题目比较好想到的就是暴力法,以列计算遍历,寻找到这一列的左右最高柱即可,只需要计算h = min(leftheight, rightheight) - height[i]。

但是我们能看到就是这个方法的弊病,每计算一个列都得遍历一遍。

这里我们就能够想到是否可以应用到单调栈,是可以的,但还用列的方式,直接获取到左右两侧的最高柱不可行了。

这里需要按照行计算,雨水高度 = min(凹槽左边高度,凹槽右边高度) - height[i]。这里凹槽左边高度是存储在栈内,凹槽右边高度即要入栈的元素。

#include <bits/stdc++.h>

using namespace std;
/*
* 作者:希希雾里
* 42.接雨水
* 讲述自己的一些理解和认知
* 单调栈:保持栈内元素有序。从大到小,从小到大
* 接雨水最核心的思路:在于找到左右两边的最高柱子
* */

/*  暴力法
*  使用暴力法可以很好的理解本题的核心思路
*  时间复杂度:O(n^2)         空间复杂度:O(1)
* */
int trap(vector<int>& height) {
    int result = 0;

    for (int i = 1; i < height.size() - 1; ++i) {
        int leftheight = height[i];
        int rightheight = height[i];

        //向左遍历,得到左柱子
        for (int l = i - 1; l >= 0; --l) {
            if(height[l] > leftheight) leftheight = height[l];
        }

        //向右遍历,得到右柱子
        for (int r = i + 1; r <= height.size() - 1; ++r) {
            if(height[r] > rightheight) rightheight = height[r];
        }

        int h = min(leftheight, rightheight) - height[i];
        if(h > 0) result += h;
    }

    return result;
}

/*
*  单调栈
*  可以由暴力法的过程中,感受到寻找左右柱子的过程中
*  我们能发现单调栈就非常的适合。
*  按行计算接水的面积
*  模拟单调栈的流程
* */
int trap2(vector<int>& height) {
    int result = 0;
    stack<int> st;
    if(height.size() <= 2) return result;
    st.push(0);

    for (int i = 1; i < height.size(); ++i) {
        if(height[i] < height[st.top()] ){              //第一种情况
            st.push(i);
        }else if(height[i] == height[st.top()]){        //第二种情况
            st.pop();
            st.push(i);
        }else{
            while(!st.empty() && height[i] > height[st.top()]){         //第三种情况
                int mid = st.top();
                st.pop();
                if(!st.empty()){
                    int h = min(height[st.top()], height[i]) - height[mid];
                    int w = i - st.top() - 1;
                    result += h * w;
                }
            }
        }
        st.push(i);
    }
    return result;
}

int main() {
    vector<int> num;
    int rain;
    while(cin >> rain){
        num.push_back(rain);
        if(getchar() == '\n'){
            break;
        }
    }

    int result = trap2(num);
    cout << result;

}

/*  测试样例
0 1 0 2 1 0 1 3 2 1 2 1
6

4 2 0 3 2 5
9
*
*
* */

84. 柱状图中最大的矩形

题目描述:

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

输入输出示例:

输入:heights = [2,1,5,6,2,3] 输出:10

输入: heights = [2,4] 输出: 4

提示:

  • 1 <= heights.length <=105
  • 0 <= heights[i] <= 104

思路和想法:

这道题目和上一道接雨水非常的相近。

#include<bits/stdc++.h>

using namespace std;

/*
* 作者:希希雾里
* 84.柱状图中最大的矩形
* 讲述自己的一些理解和认知
* 单调栈的核心:寻找左右最近大于或小于的值
* */
/*暴力解法*/
int largestRectangleArea(vector<int>& heights) {
    int sum = 0;
    for (int i = 0; i < heights.size(); i++) {
        int left = i;
        int right = i;
        /*暴力遍历找到左柱和右柱*/
        //循环边界的讨论,left:-1~height.size() - 1   right:0~height.size()
        for (; left >= 0; left--) {
            if (heights[left] < heights[i]) break;
        }
        for (; right < heights.size(); right++) {
            if (heights[right] < heights[i]) break;
        }
        int w = right - left - 1;
        int h = heights[i];
        sum = max(sum, w * h);
    }
    return sum;
}

/*双指针法*/
int largestRectangleArea2(vector<int>& heights) {
    vector<int> minLeftIndex(heights.size());
    vector<int> minRightIndex(heights.size());
    int size = heights.size();

    // 记录每个柱子 左边第一个小于该柱子的下标
    minLeftIndex[0] = -1; // 注意这里初始化,防止下面while死循环
    for (int i = 1; i < size; i++) {
        int t = i - 1;
        // 这里不是用if,而是不断向左寻找的过程
        while (t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];
        minLeftIndex[i] = t;
    }
    // 记录每个柱子 右边第一个小于该柱子的下标
    minRightIndex[size - 1] = size; // 注意这里初始化,防止下面while死循环
    for (int i = size - 2; i >= 0; i--) {
        int t = i + 1;
        // 这里不是用if,而是不断向右寻找的过程
        while (t < size && heights[t] >= heights[i]) t = minRightIndex[t];
        minRightIndex[i] = t;
    }
    // 求和
    int result = 0;
    for (int i = 0; i < size; i++) {
        int sum = heights[i] * (minRightIndex[i] - minLeftIndex[i] - 1);
        result = max(sum, result);
    }
    return result;
}


/*单调栈*/
int largestRectangleArea3(vector<int>& heights) {
    int result = 0;
    stack<int> st;
    //数组头部和尾部加入元素0
    heights.push_back(0);
    heights.insert(heights.begin(),0);
    st.push(heights[0]);


    //着重关注下角标
    for (int i = 1; i < heights.size(); ++i) {
        if(heights[i] > heights[st.top()]){             //第一种情况
            st.push(i);
        } else if(heights[i] == heights[st.top()]){     //第二种情况
            st.pop();
            st.push(i);
        }else{
            while (!st.empty() && heights[i] < heights[st.top()]){  //第三种情况
                int ref = st.top();
                st.pop();
                if(!st.empty()){
                    int left = st.top();
                    int right = i;
                    int w = right - left - 1;
                    int h = heights[ref];
                    result = max(result, h * w);
                }
            }
            st.push(i);
        }
    }
    return result;
}

int main() {
    vector<int> number;
    int num;
    while (cin >> num){
        number.push_back(num);
        if(getchar() == '\n'){
            break;
        }
    }

    int result;
    result = largestRectangleArea3(number);
    cout << result;
    return 0;
}

/* 测试样例
2 1 5 6 2 3

2 4

2 1 1 1 1 1
* */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/756186.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

我开源了团队内部基于SpringBoot Web快速开发的API脚手架stater

我们现在使用SpringBoot 做Web 开发已经比之前SprngMvc 那一套强大很多了。 但是 用SpringBoot Web 做API 开发还是不够简洁有一些。 每次Web API常用功能都需要重新写一遍。或者复制之前项目代码。于是我封装了这么一个 抽出SpringBoot Web API 每个项目必备需要重复写的模块…

【100天精通python】Day3:python的基本数据类型和数据类型转换

一. python的基本数据类型 以下是一些常见的举例和详细解释&#xff1a; 整数&#xff08;int&#xff09;&#xff1a;表示整数值。例如&#xff1a; x 5&#xff1a;将整数值5赋给变量x。 y -10&#xff1a;将整数值-10赋给变量y。 浮点数&#xff08;float&#xff09;&a…

【聚焦机器学习与实践经验的实用指南——《Python机器学习项目实战》】

《Python机器学习项目实战》引领大家在构建实际项目的过程中&#xff0c;掌握关键的机器学习概念!使用机器学习&#xff0c;我们可完成客户行为分析、价格趋势预测、风险评估等任务。要想掌握机器学习&#xff0c;需要有优质的范例、清晰的讲解和大量的练习。本书完全满足这三点…

漏洞复现-CVE-2022-24112原理与复现

目录 漏洞原理漏洞描述影响范围 apisix学习漏洞复现config.yaml环境搭建exp代码 入侵检测与修复总结参考 漏洞原理 漏洞描述 An attacker can abuse the batch-requests plugin to send requests to bypass the IP restriction of Admin API. A default configuration of Apa…

基于JavaSwing+MySQL的电影票购票管理系统

点击以下链接获取源码&#xff1a; https://download.csdn.net/download/qq_64505944/88051172?spm1001.2014.3001.5503 JDK1.8 MySQL5.7 功能&#xff1a;管理员与用户两个角色登录&#xff0c;管理员可以对电影进行增删改查处理&#xff0c;可以对影院增删改查管理&#x…

【C语言】类型转换和优先级

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在回炉重造C语言&#xff08;2023暑假&#xff09; ✈️专栏&#xff1a;【C语言航路】 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你…

【Linux系统编程】Linux第一个小程序——进度条

文章目录 1. 对回车&#xff08;\r&#xff09;和换行&#xff08;\n&#xff09;的理解1.1 概念理解1.2 测试 2. 缓冲区的理解2.1 观察现象2.2 原因解释 3. 倒计时小程序4. 进度条小程序4.1 基本思路及实现4.2 改进及优化4.3 增加百分比显示4.4 增加旋转光标4.5 给进度条配色 …

基于FT232HL的USB2.0转ARINC429板卡

基于FT232HL的USB2.0转ARINC429板卡 1 概述 《USB2.0转ARINC429板卡》采用底板子板&#xff0c;层叠安装的结构&#xff1b;使用同样的底板&#xff0c;变换不同功能的子板实现不同的功能版本。 a) 降低硬件设计复杂度&#xff1a;新板卡设计只需要设计子板&#xff0c;子板的…

类和对象(C++)( static成员、explicit、友元、内部类、匿名对象)

类和对象 static成员概念static成员“登场”特性static成员使用 注意 explicit从一段代码引入explicit和explicit相关特性 友元友元函数引入问题解决 小结 友元类 内部类概念特性 匿名对象引入使用 static成员 概念 类的静态成员&#xff1a;声明为static的类成员。 静态成员变…

【黑客】网络安全靠自学?只会毁了你!

1️⃣网安现状 ❗本文面向所有 想要涉足网安领域 或 已经涉足但仍处在迷茫期 的伙伴&#xff0c;如果你月薪达到了3w&#xff0c;那么请你离开。 如果没有&#xff0c;希望你继续看下去&#xff0c;因为你人生的转折点将从这篇文章开始。 ✈️网络安全&#xff0c;一个近几年大…

5 个能出色完成数据恢复的免费数据恢复软件知识分享。

有时&#xff0c;由于意外删除或某些问题&#xff0c;您可能会丢失 Windows 10 笔记本电脑或台式机上的重要数据。Windows 操作系统不提供任何内部工具来恢复已删除的数据。但是有一些非常好的数据恢复软件可以更专业地完成这项工作。最好的人总是有报酬的&#xff0c;但不用担…

按键精灵、auto.js等一些移动端脚本 如何连接云服务器的数据库, 进行读写操作

一、技术背景 按键手机版和auto.js&#xff0c;只支持连接本地数据库sqllite&#xff0c;该数据库只存在本地 其他设备无法读写&#xff0c;就像本地的txt一样。 而很多脚本作者的需求是&#xff1a;多个脚本&#xff0c;甚至在全国不同城市的脚本也能读取和写入同一批数据&…

AJAX-day01

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 AJAX 概念和 axios 使用 什么是 AJAX 怎么用 AJAX &#xff1f; axios 使用 认识 URL 什么是 URL&…

韦东山Linux教学视频中的makefile文件详细介绍

前言 &#xff08;1&#xff09;在学习韦东山Linux教学视频的时候&#xff0c;他的makefile并没有做详细的介绍。以至于我学了很长时间对他的makefile文件不理解。所以本文将会详细介绍韦东山Linux教学视频中的makefile文件含义。 &#xff08;2&#xff09;注意&#xff1a;我…

使用 docker-compose 部署 Jenkins

注&#xff1a;我是在虚拟机&#xff08;Ubuntu&#xff09;上部署了 docker-compose&#xff0c;然后才使用 docker-compose 部署 Jenkins&#xff01; 关于如何在 Ubuntu 部署 docker-compose&#xff0c;可以看我其它的文章。 本文目录 1. 创建 docker_jenkins_compose 目录…

【NI USRP】每一个USRP是如何命名的呢,和原厂Ettus型号有什么关联呢?

详细的硬件配置&#xff0c;非常有助于设备的选型。 如果您采购了X310子板&#xff0c;是可以将其转化为对应的USRP型号的设备。 B系列 EttusNI-USRP频段最大带宽通道B200mini无70 MHZ - 6 GHZ56 MHz1X1B200mini-i无70 MHZ - 6 GHZ56 MHz1X1B205mini-i无70 MHZ - 6 GHZ56 MHz…

三菱以太网通讯模块在哪

捷米特JM-ETH-FX采用工业级设计&#xff0c;导轨安装&#xff0c;带通讯线。不占用PLC编程口&#xff0c;上位机通过以太网对PLC数据监控的同时&#xff0c;触摸屏可以通过复用接口X2与PLC进行通讯。捷米特JM-ETH-FX支持工控领域内绝大多数SCADA软件&#xff0c;支持三菱MC以太…

C#开发的OpenRA游戏之维修按钮

C#开发的OpenRA游戏之维修按钮 前面分析物品的变卖按钮,如果理解这个流程,再看其它按钮的流程,其实是一样的,所以前面的文章是关键,只有理解通透的基础之上,才能继续往下。 维修按钮的存在价值,就是当建筑物受到敌方破坏,还没有完全倒掉之前,可以使用金币来进行修理。…

java项目之电子商城系统(ssm+mysql+jsp)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的电子商城系统。技术交流和部署相关看文章末尾&#xff01; 开发环境&#xff1a; 后端&#xff1a; 开发语言&#xff1a;Java 框架&…

对抗业务逻辑攻击:传统安全工具为何失效

随着数字环境的不断发展&#xff0c;不良行为者寻求利用应用程序漏洞的策略也在不断发展。最阴险的攻击类型之一是业务逻辑攻击 (BLA)。与可以通过签名或模式识别的已知攻击&#xff08;例如 SQL 注入攻击&#xff09;不同&#xff0c;BLA 针对应用程序内的核心功能和决策过程。…