題目描述:
給定 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;
}
};