2020年5月30日柱状图中最大的矩形largestRectangleArea
默认格式:
class Solution {
public int largestRectangleArea(int[] heights) {
}
}
解题思路:
这道题看起来非常难,至少他的解题思路不是非常容易就能找到的,要做出这道题要先有一个比较好的想法才可以。
方法1:暴力算法
暴力算法一直是我最喜欢的一种算法,因为能写出暴力算法至少证明了你对题目有了最基本的了解,那么使用暴力算法怎么解决呢?
第一步,获取数组的第一个元素,循环整个数组,获取这些子数组的矩形面积(最小高度X宽度)
第二步,获取数组的第二个元素…
第三步,获取数组的第三个元素…
第length步,获取数组的第length个元素…
比较上面获得的所有矩形的大小,最大的那个就是最大面积。
时间复杂度O(n^2)
我就不写这个算法了,对于算法能力提升没什么帮助。
方法2:双指针(以下说法仅代表我个人主观观点)
虽然感觉这两种方法能用,但是实际上发现这两种方法并不适合用在这里,因为滑动窗口和双指针都是单向移动的,意思就是这两种算法只能用在能够使用规律推断的,中间的部分元素对于结果不会有影响的情况,比如当时写的寻找子串的方法,在ABCDEFG中找到最小的包含CE的子串,那么在出现C之前的子串我们可以直接抛弃,在出现CE之后,又可以把下一个C之前的所有字符直接抛弃不处理。也就是说,我们只需要找到我们关注的内容就可以了,我们不关注的内容可以随意变为任意一个其他我们不关注的内容。
而在本题中,无法抛弃任何一个元素,所以没有办法使用这个算法。
方法3:
本来我自己想了一个算法,结果算到最后是错误的,有一些地方没想到。
实在没有思路了,今天就用暴力算法做出来,然后看答案再写一些理解吧。
int res=0;
//外层循环,每个元素进行一次
for (int i=0;i<heights.length;i++){
int min=heights[i];
for (int j=i;j<heights.length;j++){
min=Math.min(min,heights[j]);
res=Math.max(res,min*(j-i+1));
}
}
return res;
暴力算法写起来是简单,而且还可以进行一些优化,不过没啥意义,看一看别人是怎么写的。
其实没有什么特殊的,我看完之后还是觉得挺简单的,是最基础的直接使用数据结构来节省时间的方式,但是我还是没能在第一时间想出使用栈来实现。
算法的最基本的内容,找到合适的数据结构,使我们每次计算都能为后面的计算提供帮助,这样就可以节省时间。
class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
int[] left = new int[n];
int[] right = new int[n];
Stack<Integer> mono_stack = new Stack<Integer>();
for (int i = 0; i < n; ++i) {
while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
mono_stack.pop();
}
left[i] = (mono_stack.isEmpty() ? -1 : mono_stack.peek());
mono_stack.push(i);
}
mono_stack.clear();
for (int i = n - 1; i >= 0; --i) {
while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
mono_stack.pop();
}
right[i] = (mono_stack.isEmpty() ? n : mono_stack.peek());
mono_stack.push(i);
}
int ans = 0;
for (int i = 0; i < n; ++i) {
ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);
}
return ans;
}
}