题目链接:
https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
方法一:暴力法
柱子i和j范围内的最大矩形,我们可以遍历i至j去查找范围内最小的高度H,宽L为柱子i和j的距离。H*L就是柱子i和j范围内的最大矩形。
然后我们再遍历所有柱子的组合,最后在所有的情况中得到最大值。
1. class Solution {
2. public:
3. int largestRectangleArea(vector<int>& heights) {
4. int n = heights.size();
5. if (n == 0) {
6. return 0;
7. }
8.
9. int max = 0;
10. for (int i = 0; i < n; ++i) {
11. int h = heights[i];
12. for (int j = i; j < n; ++j) {
13. h = h < heights[j] ? h : heights[j];
14. int L = j - i + 1;
15. if (h == 0) {
16. break;
17. }
18. max = max > h * L ? max : h * L;
19. }
20. }
21. return max;
22. }
23. };
方法二:
我们可以分别求出包含每个柱子的最大矩形面积,然后选择最大的。
对于一个柱子求包含它的最大矩形,那么该柱子的高度必定等于矩形的高度。我们只要分别求出左右两边最近的高度小于当前柱子的下标,下标的距离即矩形的宽。当前柱子的高度即为矩形的高。
我们用leftMin[i]和rightMin[i]保存柱子i左右两边最近高度小于H的柱子下标。
特殊的,leftMin[0]=-1,rightMin[n-1] = n。
对于查找左边第一个小于柱子i的柱子下标,我们可以这样:
1.先判断是否大于左边相邻的柱子,是的话就将其下标记录至数组。
2.不是的话我们跳跃至leftMin[i-1],判断leftMin[i-1]的柱子是否小于柱子i。
如果柱子i-1高于柱子i,因为leftMin[i-1]+1至i-1均大于柱子i-1,所以该范围内的柱子也高于柱子i。
3.循环上述步骤直至找到符合条件的柱子。
1. class Solution {
2. public:
3. int largestRectangleArea(vector<int>& heights) {
4. int n = heights.size();
5. if (n == 0) {
6. return 0;
7. }
8.
9. // 保存左边小于当前高度的柱子下标
10. int leftMin[n] = {-1};
11. for (int i = 1; i < n; ++i) {
12. if (heights[i-1] < heights[i]) {
13. leftMin[i] = i-1;
14. } else {
15. // 从小于上一个柱子的柱子开始往左查找。
16. int j = leftMin[i-1];
17. while (j >=0) {
18. if (heights[j] < heights[i]) {
19. break;
20. }
21. j = leftMin[j];
22. }
23. leftMin[i] = j;
24. }
25. }
26.
27. int rightMin[n];
28. rightMin[n - 1] = n;
29.
30. for (int i = n - 2; i >= 0; --i) {
31. if (heights[i+1] < heights[i]) {
32. rightMin[i] = i+1;
33. } else {
34. // 从小于上一个柱子的柱子开始往右查找。
35. int j = rightMin[i+1];
36. while (j < n) {
37. if (heights[j] < heights[i]) {
38. break;
39. }
40. j = rightMin[j];
41. }
42. rightMin[i] = j;
43. }
44. }
45.
46. int maxSize = 0;
47. for (int i = 0; i < n; ++i) {
48. int H = heights[i];
49. int L = rightMin[i] - leftMin[i] - 1;
50. maxSize = maxSize > H * L ? maxSize : H * L;
51. }
52. return maxSize;
53. }
54. };
方法三:单调栈
原理和方法二一样,求包含柱子i的最大矩形。
我们建立一个栈,依次遍历每个柱子。
如果栈空入栈下标-1。
如果当前柱子高度大于栈顶下标所表示柱子的高度,当前柱子下标入栈。
如果当前柱子小于栈顶下标表示柱子的高度,弹出栈顶元素并记录下其高度。当前柱子下标减去新的栈顶下标减一(矩形的宽),然后乘以刚刚出栈柱子的高度(矩形的高)。
1. class Solution {
2. public:
3. int largestRectangleArea(vector<int>& heights) {
4. int n = heights.size();
5. if (n == 0) {
6. return 0;
7. }
8. stack<int> st;
9. st.push(-1);
10.
11. int maxSize = 0;
12. for (int i = 0; i < n; ++i) {
13. //cout << i << " st.top: " << st.top() << endl;
14.
15. if (st.size() > 1 && heights[i] >= heights[st.top()]) {
16. //cout << "push: " << i << endl;
17. st.push(i);
18. } else {
19. while (st.size() > 1 && heights[i] < heights[st.top()]) {
20. //cout << "pop: " << st.top() << endl;
21. int H = heights[st.top()];
22. st.pop();
23. int L = i - st.top() - 1;
24. maxSize = maxSize > H * L ? maxSize : H * L;
25. }
26. //cout << "push: " << i << endl;
27. st.push(i);
28. }
29. }
30.
31. while (st.size() > 1) {
32. int H = heights[st.top()];
33. st.pop();
34. int L = n - st.top() - 1;
35. maxSize = maxSize > H * L ? maxSize : H * L;
36. }
37.
38. return maxSize;
39. }
40. };