1、单调栈
- 保存在栈中的数据是排序的,用这种排序的栈来解决问题的方法称为单调栈法
- 如何使用? 在入栈前需要判断与栈顶元素的大小,当栈顶元素更小时执行入栈,栈顶元素更大时不断出栈。
2、LCR 039. 柱状图中最大的矩形
题目信息:
- https://leetcode.cn/problems/0ynMMM/description/
给定非负整数数组 heights ,数组中的数字用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。示例 1:
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10示例 2:
输入: heights = [2,4]
输出: 4提示:
1 <= heights.length <=105
0 <= heights[i] <= 104
3、解题思路:
3.1、解法一:暴力解法
- 两层for循环确定矩形的宽度,在这个宽度区间范围内查找高度最低的元素值,并求最终的矩形面积进行比较,最后返回最大矩形面积
- 时间复杂度为N的平方,执行超时
int largestRectangleArea1(vector<int> &heights)
{int res = 0;int count = heights.size();for (int i = 0; i < count; i++){int minH = heights[i];for (int j = i; j < count; j++){if (heights[j] < minH){minH = heights[j];}int area = minH * (j - i + 1);res = std::max(res, area);}}return res;
}
3.2、解法二:分治法:
- 在数组元素内找到最小值,以最小元素值为基准将数组分为三个区间,分别求这三个区间的矩形面积,
- 左右两个区间可以继续拆分,直到区间范围为1个宽度
int realArea(int left, int right, vector<int> &heights)
{std::cout << "left:" << left << " ,right:" << right << std::endl;if (left >= heights.size()){return 0;}if (left >= right) {return heights[left];}int minI = left;for (int i = left; i <= right; i++){if (heights[i] < heights[minI]){minI = i;}}int leftA = realArea(left, minI - 1, heights);int area = heights[minI] * (right - left + 1);int rightA = 0;if (minI < heights.size()){rightA = realArea(minI + 1, right, heights);}area = std::max(area, leftA);return std::max(area, rightA);
}int largestRectangleArea2(vector<int> &heights)
{return realArea(0, heights.size() - 1, heights);
}
3.3、解法三:单调栈解法
- 单调栈是要求在遍历数组元素的过程中,每一个遍历区间,单调栈中的元素都保持升序排序。
- 例如数组遍历过程中存在n个区间[0,0],[0,2]… [0,n-1] ,在這些区间过程中单调栈中的元素都保持升序
- 所以数组遍历过程中,需要判断遍历元素与栈顶元素的大小,如果遍历元素更大,则元素入栈,单调栈数据维持升序
- 如果遍历元素更小,那要保证该区间范围内,单调栈的升序,那就需要将栈顶元素出栈,继续判断新的栈顶元素与遍历元素的大小,
- 直至遍历元素更大(while循环),然后执行入栈,这样能保证除了栈顶哪个元素比他小,中间区域比遍历元素大的数据都出栈了,此时遍历元素就是该中间区域的最小值
- 当栈顶元素出栈时,该元素是中间区域的最小值,以该元素为高度,并进行出栈,宽度为遍历元素位置和新的栈顶元素之间范围。进行求矩形面积
- 栈中元素保存的是数组元素的下标,为更方便计算中间区域的宽度,默认将-1位置入栈
int largestRectangleArea(vector<int> &heights)
{std::stack<int> stack;stack.push(-1);int res = 0;for (int i = 0; i < heights.size(); i++){while (stack.top() != -1 && heights[stack.top()] >= heights[i]){int topI = stack.top();stack.pop();int area = heights[topI] * (i - stack.top() - 1);res = std::max(res, area);}stack.push(i);}while (stack.top() != -1){int topI = stack.top();stack.pop();int area = heights[topI] * (heights.size() - stack.top() - 1);res = std::max(res, area);}return res;
}
4、总结:
- 单调栈解法需要在入栈时判断与栈顶元素值的大小
- 矩形面积通过出栈时的元素高度,该高度为中间区域的最小值,区域的宽度为遍历位置与新的栈顶元素位置之间