前言
筆試面試中,單調棧用的也特別多,屬於數據結構類的,在這裏先總結下,免得以後忘了。這裏只講應用,不太涉及原理。
題目
1 矩形最大面積
首先來個經典例題:
求矩形的最大面積。((leetcode 85 maximal_Recetangle leetcode 84 largest_rectangle_in_histogram))
這個題目就是典型的單調棧。
運用單點棧的時候,首先想到的,應該是,建立一個單調遞增還是單調遞減的單調棧。這裏維護一個單調遞增的單調棧。每次遇到一個小於當前棧頂的數時(假設這個數爲tn),把當前棧中所有比tn大的數,全部彈出棧。彈出棧的過程中,不要忘了,在彈出的過程中,不要忘了做相應的操作(如增加矩形的寬)。
以這組數據爲例:
3 5 10 12 7 8 20
剛開始面積s = 0,首先把3入棧,然後5大於3,5入棧,10大於5,10入棧,12大於10,12入棧,7小於12,12出棧,同時s 更新爲12;10比7大,10出棧,更新s爲102 = 20。然後7入棧,這個時候,7的寬爲3(10,12,7,三個數全部壓成了7)。8入棧,20入棧。所有數遍歷完了之後,棧中內容爲3(1),5(1),7(3),8(1),20(1),s=20。20出棧,s=20,8出棧,s=max(s,82)=20,6出棧,s=max(s,6*5) = 30。。。這樣操作下去。
貼出這個題目AC的代碼:
class R {
public int x;
public int y;
public R(int x, int y) {
this.x = x;
this.y = y;
}
}
public int largestRectangleArea(int[] height) {
if(height.length==0)
return 0;
Stack<R> stack = new Stack<>();
//維護一個單調遞zeng的單調棧
int pos = 0;
int max = 0;
stack.add(new R(height[pos++], 1));
while (pos < height.length) {
\\ R tr = stack.peek();
int len = 1;
while (!stack.isEmpty() && (stack.peek().x > height[pos])) {
len += stack.peek().y;
max = Math.max((len - 1) * stack.peek().x, max);
stack.pop();
}
stack.push(new R(height[pos++], len));
}
int len = 0;
while (!stack.isEmpty()) {
len += stack.peek().y;
max = Math.max(max, len * stack.pop().x);
}
\\ System.out.print(max);
return max;
}
這是單調棧的一個典型應用,還有一個變形就是 給你一連串數字,要你找出一連串連續的數字,求出該區間段中所有數的和*該區間中最小值,也是單調棧的典型應用。
單調棧的時間複雜度,幾乎可以認爲爲線性。
單點棧還有一類題目,經常出現,那就是 區間和的最小值
區間和的最小值
下面給一個參考鏈接,已經說的很詳細了。
求數組中區間中最小數*區間所有數和的最大值
一維單調棧就說這麼多吧,下面說說二維單調棧。
2 一維單調棧進階——二維單調棧
先來一個二維單調棧的典型題目。
leetcode最大矩形面積
這裏是二維單調棧的典型應用,遍歷數組,每一層當做一個一維的單調棧去處理。關鍵在於得到單調棧的矩形,這個矩形由上面的矩形傳遞下來。如果當前a[i]爲0,則這個矩形高度爲0,如果a[i]爲1,則矩形面積爲a[i-1]+1。
AC代碼如下:
class R {
int x;
int y;
public R(int x, int y) {
this.x = x;
this.y = y;
}
}
int dp[][];
public int maximalRectangle(char[][] matrix) {
if (matrix.length == 0)
return 0;
int len1 = matrix.length;
int len2 = matrix[0].length;
dp = new int[len1][len2];
for (int i = 0; i < len1; i++) {
for (int j = 0; j < len2; j++) {
dp[i][j] = 0;
}
}
for (int i = 0; i < len2; i++) {
dp[0][i] = matrix[0][i] == '1' ? 1 : 0;
}
Stack<R> stack = new Stack<>();
int a[] = new int[len2];
a[0] = matrix[0][0] == '1' ? 1 : 0;
int max = a[0];
for (int i = 1; i < len2; i++) {
if (matrix[0][i] == '1') {
a[i] = a[i - 1] + 1;
max = Math.max(max, a[i]);
} else {
a[i] = 0;
}
}
for (int i = 1; i < len1; i++) {
for (int j = 0; j < len2; j++) {
if (matrix[i][j] == '1') {
dp[i][j] = dp[i - 1][j] + 1;
}
int len = 1;
while (!stack.isEmpty() && (stack.peek().x > dp[i][j])) {
len = len + stack.peek().y;
max = Math.max(max, (len - 1) * stack.peek().x);
stack.pop();
}
stack.push(new R(dp[i][j], len));
}
int slen = 0;
while (!stack.isEmpty()) {
// System.out.print(stack.peek().x + " " + stack.peek().y + " ");
slen += stack.peek().y;
max = Math.max(max, stack.peek().x * slen);
stack.pop();
}
// System.out.println();
}
return max;
}
這時複雜度就是在一維單調棧上面加一維。
這個題目還有一個相關變形,就是二維矩形的最大和。不過這個就完全不是單調棧的揭發了,二十動態規劃,後面有時間再總結。