怎么用C++求直方图中最大的矩形

发布时间:2022-10-17 17:23:02 作者:iii
来源:亿速云 阅读:132

怎么用C++求直方图中最大的矩形

引言

在计算机科学和算法设计中,直方图最大矩形问题是一个经典的问题。给定一个直方图,每个条形的高度代表一个非负整数,宽度为1,要求找到直方图中最大的矩形面积。这个问题在图像处理、数据分析和计算机视觉等领域有广泛的应用。

本文将详细介绍如何使用C++解决直方图最大矩形问题。我们将从问题的定义开始,逐步介绍不同的解决方法,并最终给出一个高效的C++实现。

问题定义

给定一个直方图,每个条形的高度为一个非负整数,宽度为1。要求找到直方图中最大的矩形面积。

例如,给定直方图 [2, 1, 5, 6, 2, 3],最大的矩形面积为10,对应的矩形高度为5,宽度为2。

方法一:暴力法

思路

暴力法的思路是枚举所有可能的矩形,计算每个矩形的面积,然后找到最大的面积。

具体来说,对于每个条形,我们将其作为矩形的高度,然后向左右扩展,直到遇到比当前高度小的条形为止。这样,我们就可以得到以当前条形为高度的最大矩形面积。

实现

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int largestRectangleAreaBruteForce(vector<int>& heights) {
    int maxArea = 0;
    int n = heights.size();
    
    for (int i = 0; i < n; ++i) {
        int minHeight = heights[i];
        for (int j = i; j < n; ++j) {
            minHeight = min(minHeight, heights[j]);
            int area = minHeight * (j - i + 1);
            maxArea = max(maxArea, area);
        }
    }
    
    return maxArea;
}

int main() {
    vector<int> heights = {2, 1, 5, 6, 2, 3};
    cout << "最大矩形面积: " << largestRectangleAreaBruteForce(heights) << endl;
    return 0;
}

复杂度分析

优缺点

方法二:分治法

思路

分治法的思路是将直方图分成左右两部分,分别求解左右两部分的最大矩形面积,然后考虑跨越中间的最大矩形面积。

具体来说,我们首先找到直方图中的最小高度,然后以最小高度为基准,将直方图分成左右两部分。最大矩形面积要么在左半部分,要么在右半部分,要么跨越中间的最小高度。

实现

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int largestRectangleAreaDivideAndConquer(vector<int>& heights, int left, int right) {
    if (left > right) return 0;
    
    int minIndex = left;
    for (int i = left; i <= right; ++i) {
        if (heights[i] < heights[minIndex]) {
            minIndex = i;
        }
    }
    
    int area = heights[minIndex] * (right - left + 1);
    int leftArea = largestRectangleAreaDivideAndConquer(heights, left, minIndex - 1);
    int rightArea = largestRectangleAreaDivideAndConquer(heights, minIndex + 1, right);
    
    return max(area, max(leftArea, rightArea));
}

int largestRectangleAreaDivideAndConquer(vector<int>& heights) {
    return largestRectangleAreaDivideAndConquer(heights, 0, heights.size() - 1);
}

int main() {
    vector<int> heights = {2, 1, 5, 6, 2, 3};
    cout << "最大矩形面积: " << largestRectangleAreaDivideAndConquer(heights) << endl;
    return 0;
}

复杂度分析

优缺点

方法三:单调栈法

思路

单调栈法的思路是利用栈来维护一个递增的条形高度序列。对于每个条形,我们将其高度与栈顶元素的高度进行比较。如果当前条形的高度小于栈顶元素的高度,则弹出栈顶元素,并计算以栈顶元素为高度的最大矩形面积。

具体来说,我们遍历直方图中的每个条形,将其索引压入栈中。当遇到一个比栈顶元素小的条形时,我们弹出栈顶元素,并计算以该元素为高度的最大矩形面积。这个矩形的宽度为当前索引与栈顶元素索引的差值减1。

实现

#include <iostream>
#include <vector>
#include <stack>

using namespace std;

int largestRectangleAreaMonotonicStack(vector<int>& heights) {
    stack<int> s;
    heights.push_back(0); // 添加一个高度为0的条形,确保所有条形都被处理
    int maxArea = 0;
    int n = heights.size();
    
    for (int i = 0; i < n; ++i) {
        while (!s.empty() && heights[i] < heights[s.top()]) {
            int height = heights[s.top()];
            s.pop();
            int width = s.empty() ? i : (i - s.top() - 1);
            maxArea = max(maxArea, height * width);
        }
        s.push(i);
    }
    
    return maxArea;
}

int main() {
    vector<int> heights = {2, 1, 5, 6, 2, 3};
    cout << "最大矩形面积: " << largestRectangleAreaMonotonicStack(heights) << endl;
    return 0;
}

复杂度分析

优缺点

方法四:动态规划法

思路

动态规划法的思路是利用两个数组leftright来记录每个条形向左和向右扩展的最大宽度。然后,对于每个条形,我们可以计算以该条形为高度的最大矩形面积。

具体来说,left[i]表示第i个条形向左扩展的最大宽度,right[i]表示第i个条形向右扩展的最大宽度。然后,最大矩形面积为heights[i] * (right[i] - left[i] + 1)

实现

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int largestRectangleAreaDynamicProgramming(vector<int>& heights) {
    int n = heights.size();
    if (n == 0) return 0;
    
    vector<int> left(n), right(n);
    
    // 计算每个条形向左扩展的最大宽度
    left[0] = 0;
    for (int i = 1; i < n; ++i) {
        int p = i - 1;
        while (p >= 0 && heights[p] >= heights[i]) {
            p = left[p] - 1;
        }
        left[i] = p + 1;
    }
    
    // 计算每个条形向右扩展的最大宽度
    right[n - 1] = n - 1;
    for (int i = n - 2; i >= 0; --i) {
        int p = i + 1;
        while (p < n && heights[p] >= heights[i]) {
            p = right[p] + 1;
        }
        right[i] = p - 1;
    }
    
    // 计算最大矩形面积
    int maxArea = 0;
    for (int i = 0; i < n; ++i) {
        maxArea = max(maxArea, heights[i] * (right[i] - left[i] + 1));
    }
    
    return maxArea;
}

int main() {
    vector<int> heights = {2, 1, 5, 6, 2, 3};
    cout << "最大矩形面积: " << largestRectangleAreaDynamicProgramming(heights) << endl;
    return 0;
}

复杂度分析

优缺点

结论

本文介绍了四种不同的方法来解决直方图最大矩形问题:暴力法、分治法、单调栈法和动态规划法。每种方法都有其优缺点,适用于不同的场景。

在实际应用中,单调栈法和动态规划法是最常用的方法,因为它们的时间复杂度最低,适用于大规模数据。如果你对算法的实现有较高的要求,建议使用单调栈法或动态规划法。

参考代码

以下是使用单调栈法的完整C++代码:

#include <iostream>
#include <vector>
#include <stack>

using namespace std;

int largestRectangleAreaMonotonicStack(vector<int>& heights) {
    stack<int> s;
    heights.push_back(0); // 添加一个高度为0的条形,确保所有条形都被处理
    int maxArea = 0;
    int n = heights.size();
    
    for (int i = 0; i < n; ++i) {
        while (!s.empty() && heights[i] < heights[s.top()]) {
            int height = heights[s.top()];
            s.pop();
            int width = s.empty() ? i : (i - s.top() - 1);
            maxArea = max(maxArea, height * width);
        }
        s.push(i);
    }
    
    return maxArea;
}

int main() {
    vector<int> heights = {2, 1, 5, 6, 2, 3};
    cout << "最大矩形面积: " << largestRectangleAreaMonotonicStack(heights) << endl;
    return 0;
}

希望本文对你理解和使用C++解决直方图最大矩形问题有所帮助!

推荐阅读:
  1. C++ 实现求小于n的最大素数的实例
  2. java中如何使用枚举法求直方图中最大矩形面积

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c++

上一篇:C++跳跃游戏问题怎么解决

下一篇:C++收集雨水问题怎么解决

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》