题目描述:
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
方法一:暴力解法O(N^2)复杂度,超时,仅提供思路(踩坑)
直接枚举每一段,找最小。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int len=heights.size();
int max_area=0;
for(int i=0;i<len;i++)
{
int min_cur=heights[i];
for(int j=i;j<len;j++)
{
min_cur=min(min_cur,heights[j]);
max_area=max(max_area,(j-i+1)*min_cur);
}
}
return max_area;
}
};
方法二:分治的思路,每次将区间分为,最小值,最小值的左半部分,最小值的右半部分。
最大值为,当前区间长度乘以最小值,左半部分最大值,右半部分最大值三者中的最大值。找最小值部分直接枚举查找的情况,针对排好序的数组时间复杂度退化为O(n^2),依旧超时哦,测试用例[1,1,...,1,1]
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int len=heights.size();
int max_area=calculateMaxArea(0,len-1,heights);
return max_area;
}
int calculateMaxArea(int left,int right,vector<int>& heights)
{
if(left>right)return 0;
int min_current_pos=left;
for(int i=left+1;i<=right;i++)
if(heights[min_current_pos]>heights[i])min_current_pos=i;
int max_left=calculateMaxArea(left,min_current_pos-1,heights);
int max_right=calculateMaxArea(min_current_pos+1,right,heights);
int max_area_include_min_value=(right-left+1)*heights[min_current_pos];
return max(max_area_include_min_value,max(max_left,max_right));
}
};
方法三:分治法+线段树维护查询,时间复杂度将为O(n*logn)。不超时,可以通过。
class Solution {
struct node
{
int start_index;
int end_index;
int min_index;
node *left;
node *right;
};
public:
int largestRectangleArea(vector<int>& heights) {
int len=heights.size();
node* root=buildSegmentTree(0,len-1,heights);
int max_area=calculateMaxArea(0,len-1,heights,root);
return max_area;
}
int calculateMaxArea(int left,int right,vector<int>& heights,node* root)
{
if(left>right)return 0;
int min_current_pos;
min_current_pos=querySegmentTree(left,right,heights,root);
int max_left=calculateMaxArea(left,min_current_pos-1,heights,root);
int max_right=calculateMaxArea(min_current_pos+1,right,heights,root);
int max_area_include_min_value=(right-left+1)*heights[min_current_pos];
return max(max_area_include_min_value,max(max_left,max_right));
}
node* buildSegmentTree(int left,int right,vector<int>& heights)
{
if(left>right)
{
return nullptr;
}
node *p=new node();
p->start_index=left;
p->end_index=right;
if(left==right)
{
p->left=p->right=nullptr;
p->min_index=left;
return p;
}
int mid=(left+right)/2;
p->left=buildSegmentTree(left,mid,heights);
p->right=buildSegmentTree(mid+1,right,heights);
p->start_index=left;
p->end_index=right;
p->min_index=heights[p->left->min_index]<heights[p->right->min_index]?p->left->min_index:p->right->min_index;
return p;
}
int querySegmentTree(int left,int right,vector<int>&heights,node* root)
{
if(left<=root->start_index&&right>=root->end_index)
{
return root->min_index;
}
int mid=(root->start_index+root->end_index)/2;
int min_left_index=-1;
int min_right_index=-1;
if(mid>=left)
{
min_left_index=querySegmentTree(left,right,heights,root->left);
}
if(mid+1<=right)
{
min_right_index=querySegmentTree(left,right,heights,root->right);
}
if(min_left_index!=-1&&min_right_index!=-1)
return heights[min_left_index]<heights[min_right_index]?min_left_index:min_right_index;
else if(min_left_index!=-1)return min_left_index;
else return min_right_index;
}
};
方法四:栈的方法。最开始把-1加入栈顶。当a[i-1]<=a[i]时,将a[i]加入到栈中。当a[i-1]>a[i]时,将a[top](top=i-1,i-2...)依次弹出,直到a[stack[j]]<=a[i],此时以弹出元素的为矩形高度的最大面积为,(i-stack[top-1]-1)*a[stack[top]]。然后将a[i]加入到栈中。当到达数组尾部时,将栈顶元素依次弹出,此时以栈顶元素为矩形高度的最大面积为(height.length-stack[top-1]-1)*a[stack[top]]。可以通过比较新矩形的面积来维护最大面积。时间复杂度将为O(n)。不超时,可以通过。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int len=heights.size();
stack<int>index_stack;
index_stack.push(-1);
int max_area=0;
for(int i=0;i<len;i++)
{
while(index_stack.top()!=-1&&heights[index_stack.top()]>heights[i])
{
int index_top=index_stack.top();
index_stack.pop();
max_area=max(max_area,heights[index_top]*(i-index_stack.top()-1));
}
index_stack.push(i);
}
while(index_stack.top()!=-1)
{
int index_top=index_stack.top();
index_stack.pop();
max_area=max(max_area,heights[index_top]*(len-index_stack.top()-1));
}
return max_area;
}
};