欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

leetcode84. Largest Rectangle in Histogram 分治+线段树

程序员文章站 2022-05-13 19:58:15
...

题目大意:输入一个整数数组,每个整数表示一个宽度为1的矩形,相邻整数对应的矩形相邻,求所有矩形的区域里面,围成的面积最大矩形的面积。

链接:https://leetcode.com/problems/largest-rectangle-in-histogram/

我们以输入[2,1,5,6,2,3]为例。

最大的矩形是高度为5的矩形和高度为6的矩形构成的,面积为10。

我们可以发现,给定起始和终止的两个矩形,这两个矩形围成的面积取决于这个区间内最矮的那个矩形。例如我求以第一个矩形起始,以最后一个矩形结尾的面积。这个面积取决于这个区间内最矮的矩形高度1,这个面积为1×(5-0+1)=6。

所以一开始我的思路就是分治的思路:最大的矩形面积,

要么是0~5最矮的矩形的高×(0~5区间长度)

要么是最矮矩形右边区域的最大面积。(递归求解)

要么是最矮矩形左边区域的最大面积。(递归求解)

最大矩形面积就是求三者的最大值。

那么这里还涉及到一个问题,就是如何找最矮的矩形,我一开始的想法就是线性查找,但这是一种效率很低的查找方式。这是我一开始的求解代码,800多毫秒的运行时间:

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        if(heights.size()==0) return 0;
        return largest(heights,0,heights.size()-1);
    }
    int largest(vector<int>& heights,int l,int r){
        //cout<<"l="<<l<<" r="<<r<<endl;
        if(l==r) return heights[l];
        else if(l>r) return 0;
        
        int min=heights[l],min_index=l;
        for(unsigned int i=l;i<=r;++i){
            if(heights[i]<min){
                min=heights[i];
                min_index=i;
            }
        }
        
        int num1=min*(r-l+1);
        int num2=largest(heights,l,min_index-1);
        int num3=largest(heights,min_index+1,r);
        int ret=max(num1,num2);
        ret=max(ret,num3);
        return ret;
    }
};

其实分治法的思路没有问题,就是查找最矮矩形使用的方法可以再优化。这道题我们的需求就是查找某个区间上的最值问题。区间查找(根据网上答案提示),可以用线段树。于是我修改了一下,得到了优化以后的方法,运行时间20ms:

struct SegNode{
    int l,r;//interval[l,r]
    int index;//最小高度的下标
};
class Solution {
public:
    vector<SegNode> seg_tree;
    
    int largestRectangleArea(vector<int>& heights) {
        if(heights.size()==0) return 0;
        else if(heights.size()==1) return heights[0];
        
        seg_tree.resize(4*heights.size());
        buildSegmentTree(heights,1,0,(int)heights.size()-1);
        
        return largest(heights,0,heights.size()-1);
    }
    
    void buildSegmentTree(vector<int>& heights,int index,int l,int r);
    
    int search(vector<int>& heights,int index,int l,int r);
    
    int largest(vector<int>& heights,int l,int r){
        if(l>r) return 0;
        else if(l==r) {
            //cout<<"largest"<<"  l="<<l<<"  r="<<r<<"  ret="<<heights[l]<<endl;
            return heights[l];
        }
        
        int min_index=search(heights,1,l,r);
        
        //cout<<"min_index="<<min_index<<endl;
        
        int num1=heights[min_index]*(r-l+1);
        
        int num2=largest(heights,l,min_index-1);
        
        //cout<<"num2="<<num2<<endl;
        
        int num3=largest(heights,min_index+1,r);
        
        //cout<<"num3="<<num3<<endl;
        
        int ret=max(num1,num2);
        ret=max(ret,num3);
        //cout<<"largest"<<"  l="<<l<<"  r="<<r<<"  ret="<<ret<<endl;
        return ret;
    }
};


void Solution::buildSegmentTree(vector<int>& heights,int index,int l,int r){
    if(l==r){
        seg_tree[index].l=seg_tree[index].r=l;
        seg_tree[index].index=l;
        //cout<<"l="<<l<<" r="<<r<<"  index="<<seg_tree[index].index<<endl;
        return;
    }
    int mid=(l+r)/2;
    
    buildSegmentTree(heights,index<<1,l,mid);
    buildSegmentTree(heights,(index<<1)|1,mid+1,r);
    seg_tree[index].l=l;
    seg_tree[index].r=r;
    
    
    int l_min=seg_tree[index<<1].index;
    int r_min=seg_tree[(index<<1)|1].index;
    if(heights[l_min]<heights[r_min]) seg_tree[index].index=l_min;
    else seg_tree[index].index=r_min;
    
    
    //cout<<"l="<<l<<" r="<<r<<"  index="<<seg_tree[index].index<<endl;
    return;
}

//interval[l,r],minimun index
int Solution::search(vector<int>& heights,int index,int l,int r){
    int mid=(l+r)/2;
    if(l<=seg_tree[index].l && r>=seg_tree[index].r) return seg_tree[index].index;
    
    int num1=INT_MAX;
    if(l<=seg_tree[index<<1].r){
        num1=search(heights,index<<1,l,r);
    }
    
    int num2=INT_MAX;
    if(r>=seg_tree[(index<<1)|1].l) num2=search(heights,(index<<1)|1,l,r);
    
    if(num1!=INT_MAX && num2!=INT_MAX){
        if(heights[num1]<heights[num2]) return num1;
        else return num2;
    }else if(num1==INT_MAX) return num2;
    else return num1;
    
}

 

相关标签: 分治法