很简单,很有趣的一类题,好像在CF上出现过。。不太记得了
题意是给你N个1*N的矩形排列,要你框一个框,使得框出来的面积最大,就像这样:
也就是说,一个高度,他要向后扩展的条件是,它后面的所有矩形高度不小于它。
考虑一种最简单的情况,若整个矩形阵是升序的,那么显然 ans = max(ans,h[i] * (n - i));
若序列不是升序的,那么对于任意位置的矩形,考虑仅向右拓展的情况,它前面的矩形只有小于它的高度的部分,以及它后面的矩形只有大于等于它,才能将这个矩形完整包括在内,如上右图的(5,6),对于5来说,6只有5的部分才有用。那么我们只要把整个序列强行变成升序的就好了。
这里可以利用栈来实现,当h[i] >= height.top()时,压栈
当h[i] < height.top()时,弹栈,直到满足h[i] >= height.top()时,压栈,再将与弹栈数量相同的h[i]压栈
首先可以肯定,我们构造的栈一定是升序的,那么如上图,当我们构造到
(1,1,5,6)(第一个1因为上述步骤压入),当2来到时,我们需要把(5,6)弹出
在弹出的过程中万一有最优解呢?
所以我们需要记录弹出时能够构造的最大矩形,显然,也应该是ans = max(ans,height.top()*cnt),这里的cnt指弹栈数量
比如6弹出,应该记录1*6,然后5弹出,cnt++,记录2*5
当height.top()==1时,将3个2压栈,至此,(1,1,6,5)->(1,1,2,2,2)
所以整个流程是这样的:
2来到->(2)
-> 1来到 -> 2弹出,将两个1压入 -> (1,1) //记录了2*1
-> 5来到 -> (1,1,5)
-> 6来到 -> (1,1,5,6)
-> 2来到 -> 6,5弹栈 -> 3个2压入 ->(1,1,2,2,2) //记录了6*1 5*2
-> 3来到 -> (1,1,2,2,2,3)
再按推出的升序的ans公式扫一遍即可~
我觉得单调栈也能做,反正就是利用单调性做文章就行了
code:
1 class Solution { 2 public: 3 int largestRectangleArea(vector<int>& heights) { 4 stack<int>hei; 5 int ans = 0; 6 for (int i = 0; i < heights.size(); ++i) { 7 if (hei.empty() || hei.top() <= heights[i]) { 8 hei.push(heights[i]); 9 } 10 else { 11 int len = 1; 12 while (!hei.empty() && hei.top() > heights[i]) { 13 ans = max(ans, len*hei.top()); 14 hei.pop(); 15 len++; 16 } 17 while(len--) hei.push(heights[i]); 18 } 19 } 20 int len = 1; 21 while (!hei.empty()) { 22 ans = max(ans, hei.top()*len); 23 //cout << hei.top() << endl; 24 hei.pop(); 25 len++; 26 } 27 return ans; 28 } 29 };
然后#85 给你一个二维矩阵,要框出其中最大的全1矩形
只要知道从上往下看,假如有0就代表断了
简单来说就是如果当前这一行的这个位置是0,那么height[i]=0,不是0,就height[i]++;
然后用上面的代码跑N次就行啦
code:
1 class Solution { 2 public: 3 int maximalRectangle(vector<vector<char>>& matrix) { 4 vector<int>height; 5 int ans = 0; 6 for(int i = 0; i < matrix.size(); ++i){ 7 for(int j = 0; j < matrix[i].size(); ++j){ 8 if(i == 0){ 9 if(matrix[i][j] == ‘0‘) height.push_back(0); 10 else height.push_back(1); 11 } 12 else{ 13 if(matrix[i][j] == ‘0‘) height[j] = 0; 14 else height[j] += 1; 15 } 16 } 17 ans = max(ans,solve(height)); 18 } 19 return ans; 20 } 21 private: 22 int solve(vector<int> heights) { 23 stack<int>hei; 24 int ans = 0; 25 for (int i = 0; i < heights.size(); ++i) { 26 if (hei.empty() || hei.top() <= heights[i]) { 27 hei.push(heights[i]); 28 } 29 else { 30 int len = 1; 31 while (!hei.empty() && hei.top() > heights[i]) { 32 ans = max(ans, len*hei.top()); 33 hei.pop(); 34 len++; 35 } 36 while (len--) hei.push(heights[i]); 37 } 38 } 39 int len = 1; 40 while (!hei.empty()) { 41 ans = max(ans, hei.top()*len); 42 //cout << hei.top() << endl; 43 hei.pop(); 44 len++; 45 } 46 return ans; 47 } 48 };
其实和扫描线有点类似?