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

该博客探讨了LeetCode 84题的解决方案,通过分治策略和线段树来寻找矩形数组中最大的矩形面积。文章以数组[2,1,5,6,2,3]为例,说明最大矩形面积的计算取决于区间内最矮矩形的高度。作者最初采用线性搜索,但发现效率低下,后来改用线段树优化,将运行时间降低到20ms。" 127205897,12368458,高效迁移:MySQL百万数据量到Redis的实践,"['数据库迁移', '缓存优化', 'Redis操作', 'MySQL操作']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:输入一个整数数组,每个整数表示一个宽度为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;
    
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值