单调栈
在一维数组中找第一个满足某种条件的数,这种feel的东西一看就是单调栈
题目1
/**
* 题目Id:739
* 题目:每日温度
* 内容: //给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指在第 i 天之后,才会有更高的温度
//。如果气温在这之后都不会升高,请在该位置用 0 来代替。
//
//
//
// 示例 1:
//
//
//输入: temperatures = [73,74,75,71,69,72,76,73]
//输出: [1,1,4,2,1,1,0,0]
//
//
// 示例 2:
//
//
//输入: temperatures = [30,40,50,60]
//输出: [1,1,1,0]
//
//
// 示例 3:
//
//
//输入: temperatures = [30,60,90]
//输出: [1,1,0]
//
//
//
// 提示:
//
//
// 1 <= temperatures.length <= 10⁵
// 30 <= temperatures[i] <= 100
//
// Related Topics 栈 数组 单调栈 👍 1075 👎 0
* 日期:2022-03-26 12:03:08
*/
//给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指在第 i 天之后,才会有更高的温度
//。如果气温在这之后都不会升高,请在该位置用 0 来代替。
//
//
//
// 示例 1:
//
//
//输入: temperatures = [73,74,75,71,69,72,76,73]
//输出: [1,1,4,2,1,1,0,0]
//
//
// 示例 2:
//
//
//输入: temperatures = [30,40,50,60]
//输出: [1,1,1,0]
//
//
// 示例 3:
//
//
//输入: temperatures = [30,60,90]
//输出: [1,1,0]
//
//
//
// 提示:
//
//
// 1 <= temperatures.length <= 10⁵
// 30 <= temperatures[i] <= 100
//
// Related Topics 栈 数组 单调栈 👍 1075 👎 0
package leetcode.editor.cn;
import java.util.Arrays;
import java.util.Stack;
import java.util.stream.Collectors;
public class P739DailyTemperatures {
public static void main(String[] args) {
Solution solution = new P739DailyTemperatures().new Solution();
int[] tmeps = new int[]{73,74,75,71,69,72,76,73};
int[] ints = solution.dailyTemperatures(tmeps);
String result = Arrays.stream(ints).mapToObj(Integer::toString).collect(Collectors.joining(","));
System.out.println("Hello world" + result);
}
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
Stack<Integer> stack = new Stack<>();
int[] ans = new int[temperatures.length];
for (int i = 0; i < temperatures.length; i++) {
if (stack.isEmpty()) {
stack.push(i);
continue;
}
while (!stack.isEmpty()) {
Integer top = stack.peek();
if (temperatures[i] > temperatures[top]) {
ans[top] = i - top;
stack.pop();
} else {
break;
}
}
stack.push(i);
}
while (!stack.isEmpty()) {
ans[stack.pop()] = 0;
}
return ans;
}
}
//leetcode submit region end(Prohibit modification and deletion)
}
更新的解法:
KMP
时间复杂度O(n)
空间复杂度O(1)
该思路由KMP中失配数组的构造演变而来。假设ans[i]记录了i位置上的答案(向右找多少个比自己大),则求ans[i]时,我先看一眼i+1位置,如果T[i+1]比我大,那得了,答案就是它了。
否则我要找的位置至少是比T[i+1]大,那么当然我就看一看ans[i+1]
class Solution:
def dailyTemperatures(self, T: List[int]) -> List[int]:
n=len(T)
ans=[0]*n
for i in range(n-2,-1,-1):
now=i+1
while T[now]<=T[i]:
if ans[now]:
now+=ans[now]
else:
break
else:
ans[i]=now-i
return ans
题目3:
代码:
/**
* 题目Id:84
* 题目:柱状图中最大的矩形
* 内容: //给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
//
// 求在该柱状图中,能够勾勒出来的矩形的最大面积。
//
//
//
// 示例 1:
//
//
//
//
//输入:heights = [2,1,5,6,2,3]
//输出:10
//解释:最大的矩形为图中红色区域,面积为 10
//
//
// 示例 2:
//
//
//
//
//输入: heights = [2,4]
//输出: 4
//
//
//
// 提示:
//
//
// 1 <= heights.length <=10⁵
// 0 <= heights[i] <= 10⁴
//
// Related Topics 栈 数组 单调栈 👍 1839 👎 0
* 日期:2022-03-27 11:44:47
*/
//给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
//
// 求在该柱状图中,能够勾勒出来的矩形的最大面积。
//
//
//
// 示例 1:
//
//
//
//
//输入:heights = [2,1,5,6,2,3]
//输出:10
//解释:最大的矩形为图中红色区域,面积为 10
//
//
// 示例 2:
//
//
//
//
//输入: heights = [2,4]
//输出: 4
//
//
//
// 提示:
//
//
// 1 <= heights.length <=10⁵
// 0 <= heights[i] <= 10⁴
//
// Related Topics 栈 数组 单调栈 👍 1839 👎 0
package leetcode.editor.cn;
import java.util.Stack;
public class P84LargestRectangleInHistogram {
public static void main(String[] args) {
Solution solution = new P84LargestRectangleInHistogram().new Solution();
int[] heights = new int[]{2,1,5,6,2,3};
int i = solution.largestRectangleArea(heights);
System.out.println("Hello world" + i);
}
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public int largestRectangleArea(int[] heights) {
Stack<Integer> stack = new Stack<>();
int max = 0;
for (int i = 0; i < heights.length;i++) {
/*if (stack.isEmpty()) {
stack.push(i);
}*/
// 结算栈顶
while (!stack.isEmpty() && heights[i] < heights[stack.peek()]) {
max = calArea(heights, stack, max, i);
}
stack.push(i);
}
// 栈不为空,则数据已经刚好越界,并且全部加到栈里面了。
while (!stack.isEmpty()) {
max = calArea(heights, stack, max, heights.length);
/*int right = heights.length;
Integer cur = stack.pop();
int left = stack.isEmpty() ? -1 : stack.peek();
int area = (right - left - 1) * heights[cur];
max = Math.max(max, area);*/
}
return max;
}
private int calArea(int[] heights, Stack<Integer> stack, int max, int i) {
// 右边界
int right = i;
// 当前的结算点
Integer cur = stack.pop();
// 左边界
int left = stack.isEmpty() ? -1 : stack.peek();
// 面积
int area = (right - left - 1) * heights[cur];
max = Math.max(max, area);
return max;
}
}
//leetcode submit region end(Prohibit modification and deletion)
}
题目4
/**
* 题目Id:85
* 题目:最大矩形
* 内容: //给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
* //
* //
* //
* // 示例 1:
* //
* //
* //输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"]
* //,["1","0","0","1","0"]]
* //输出:6
* //解释:最大矩形如上图所示。
* //
* //
* // 示例 2:
* //
* //
* //输入:matrix = []
* //输出:0
* //
* //
* // 示例 3:
* //
* //
* //输入:matrix = [["0"]]
* //输出:0
* //
* //
* // 示例 4:
* //
* //
* //输入:matrix = [["1"]]
* //输出:1
* //
* //
* // 示例 5:
* //
* //
* //输入:matrix = [["0","0"]]
* //输出:0
* //
* //
* //
* //
* // 提示:
* //
* //
* // rows == matrix.length
* // cols == matrix[0].length
* // 1 <= row, cols <= 200
* // matrix[i][j] 为 '0' 或 '1'
* //
* // Related Topics 栈 数组 动态规划 矩阵 单调栈 👍 1220 👎 0
* <p>
* 日期:2022-03-27 12:28:17
*/
//给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
//
//
//
// 示例 1:
//
//
//输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"]
//,["1","0","0","1","0"]]
//输出:6
//解释:最大矩形如上图所示。
//
//
// 示例 2:
//
//
//输入:matrix = []
//输出:0
//
//
// 示例 3:
//
//
//输入:matrix = [["0"]]
//输出:0
//
//
// 示例 4:
//
//
//输入:matrix = [["1"]]
//输出:1
//
//
// 示例 5:
//
//
//输入:matrix = [["0","0"]]
//输出:0
//
//
//
//
// 提示:
//
//
// rows == matrix.length
// cols == matrix[0].length
// 1 <= row, cols <= 200
// matrix[i][j] 为 '0' 或 '1'
//
// Related Topics 栈 数组 动态规划 矩阵 单调栈 👍 1220 👎 0
package leetcode.editor.cn;
import java.util.Stack;
public class P85MaximalRectangle {
public static void main(String[] args) {
Solution solution = new P85MaximalRectangle().new Solution();
System.out.println("Hello world");
}
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public int maximalRectangle(char[][] matrix) {
int max = 0;
int[] cacheUp = new int[matrix[0].length];
int[] height = new int[matrix[0].length];
for (int row = 0; row < matrix.length; row++) {
for (int col = 0; col < matrix[0].length; col++) {
if (matrix[row][col] == '0') {
height[col] = 0;
cacheUp[col] = 0;
} else {
height[col] = (matrix[row][col] - '0') + cacheUp[col];
cacheUp[col] = height[col];
}
}
max = Math.max(max, largestRectangleArea(height));
}
return max;
}
public int largestRectangleArea(int[] heights) {
Stack<Integer> stack = new Stack<>();
int max = 0;
for (int i = 0; i < heights.length; i++) {
// 结算栈顶
while (!stack.isEmpty() && heights[i] < heights[stack.peek()]) {
max = calArea(heights, stack, max, i);
}
stack.push(i);
}
// 栈不为空,则数据已经刚好越界,并且全部加到栈里面了。
while (!stack.isEmpty()) {
max = calArea(heights, stack, max, heights.length);
}
return max;
}
private int calArea(int[] heights, Stack<Integer> stack, int max, int i) {
// 右边界
int right = i;
// 当前的结算点
Integer cur = stack.pop();
// 左边界
int left = stack.isEmpty() ? -1 : stack.peek();
// 面积
int area = (right - left - 1) * heights[cur];
max = Math.max(max, area);
return max;
}
}
//leetcode submit region end(Prohibit modification and deletion)
}
题目5
/**
* 题目Id:316
* 题目:去除重复字母
* 内容: //给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
//
//
//
// 示例 1:
//
//
//输入:s = "bcabc"
//输出:"abc"
//
//
// 示例 2:
//
//
//输入:s = "cbacdcbc"
//输出:"acdb"
//
//
//
// 提示:
//
//
// 1 <= s.length <= 10⁴
// s 由小写英文字母组成
//
//
//
//
// 注意:该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-
//distinct-characters 相同
// Related Topics 栈 贪心 字符串 单调栈 👍 693 👎 0
* 日期:2022-03-27 12:51:26
*/
//给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
//
//
//
// 示例 1:
//
//
//输入:s = "bcabc"
//输出:"abc"
//
//
// 示例 2:
//
//
//输入:s = "cbacdcbc"
//输出:"acdb"
//
//
//
// 提示:
//
//
// 1 <= s.length <= 10⁴
// s 由小写英文字母组成
//
//
//
//
// 注意:该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-
//distinct-characters 相同
// Related Topics 栈 贪心 字符串 单调栈 👍 693 👎 0
package leetcode.editor.cn;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
public class P316RemoveDuplicateLetters {
public static void main(String[] args) {
Solution solution = new P316RemoveDuplicateLetters().new Solution();
//String s = "bbcaac";
String s = "bcabc";
//s = "abacb";
System.out.println("Hello world : " + solution.removeDuplicateLetters(s));
s = "cbacdcbc";
System.out.println("Hello world : " + solution.removeDuplicateLetters(s));
s = "abacb";
System.out.println("Hello world : " + solution.removeDuplicateLetters(s));
}
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public String removeDuplicateLetters(String s) {
Map<Character, Integer> letterCntMap = new HashMap<>();
Map<Character, Boolean> status = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
if (letterCntMap.containsKey(s.charAt(i))) {
letterCntMap.put(s.charAt(i), letterCntMap.get(s.charAt(i))+1);
} else {
letterCntMap.put(s.charAt(i), 1);
}
}
Stack<Character> stack = new Stack<>();
for (int i = 0; i < s.length(); i++) {
// 针对一个新的值,之前还没进过栈,那么该值要看看是否比之前的值要小,小则弹出处理
if (status.get(s.charAt(i)) == null || !status.get(s.charAt(i))) {
while (!stack.isEmpty()) {
Character top = stack.peek();
// 当前的值更小,之前的栈里的元素要看看是否要弹出
if (s.charAt(i) < top) {
if (letterCntMap.get(top) > 1) {
// 扔掉一个,后面还有
letterCntMap.put(top, letterCntMap.get(top) - 1);
status.put(top, false);
stack.pop();
} else {
break;
}
} else if (s.charAt(i) == stack.peek()) {
letterCntMap.put(top, letterCntMap.get(top) - 1);
break;
} else {
break;
}
}
stack.push(s.charAt(i));
status.put(s.charAt(i), true);
} else {
letterCntMap.put(s.charAt(i), letterCntMap.get(s.charAt(i)) - 1);
}
}
StringBuilder sb = new StringBuilder();
while (!stack.isEmpty()) {
sb.append(stack.pop());
}
return sb.reverse().toString();
}
}
//leetcode submit region end(Prohibit modification and deletion)
}
题目6
对于两个相同长度的数字序列,最左边不同的数字决定了这两个数字的大小,例如,对于 A = 1axxxA=1axxx,B = 1bxxxB=1bxxx,如果 a > b 则 A > B。
基于此,我们可以知道,若要使得剩下的数字最小,需要保证靠前的数字尽可能小。
因此我们使用单调栈来维护数组的有序性。
一旦遇见s[i+1] < s[i]的时候,这时候如果我们还能删除数字那么我们就应该尝试去删除它。
代码:
/**
* 题目Id:402
* 题目:移掉 K 位数字
* 内容: //给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。
//
//
// 示例 1 :
//
//
//输入:num = "1432219", k = 3
//输出:"1219"
//解释:移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219 。
//
//
// 示例 2 :
//
//
//输入:num = "10200", k = 1
//输出:"200"
//解释:移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
//
//
// 示例 3 :
//
//
//输入:num = "10", k = 2
//输出:"0"
//解释:从原数字移除所有的数字,剩余为空就是 0 。
//
//
//
//
// 提示:
//
//
// 1 <= k <= num.length <= 10⁵
// num 仅由若干位数字(0 - 9)组成
// 除了 0 本身之外,num 不含任何前导零
//
// Related Topics 栈 贪心 字符串 单调栈 👍 758 👎 0
* 日期:2022-03-27 17:20:09
*/
//给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。
//
//
// 示例 1 :
//
//
//输入:num = "1432219", k = 3
//输出:"1219"
//解释:移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219 。
//
//
// 示例 2 :
//
//
//输入:num = "10200", k = 1
//输出:"200"
//解释:移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
//
//
// 示例 3 :
//
//
//输入:num = "10", k = 2
//输出:"0"
//解释:从原数字移除所有的数字,剩余为空就是 0 。
//
//
//
//
// 提示:
//
//
// 1 <= k <= num.length <= 10⁵
// num 仅由若干位数字(0 - 9)组成
// 除了 0 本身之外,num 不含任何前导零
//
// Related Topics 栈 贪心 字符串 单调栈 👍 758 👎 0
package leetcode.editor.cn;
import java.util.Stack;
public class P402RemoveKDigits {
public static void main(String[] args) {
Solution solution = new P402RemoveKDigits().new Solution();
String s = solution.removeKdigits("1432219", 3);
System.out.println("ans " + s);
s = solution.removeKdigits("10200", 1);
System.out.println("ans " + s);
s = solution.removeKdigits("1223459", 3);
System.out.println("ans " + s);
s = solution.removeKdigits("100", 1);
System.out.println("ans " + s);
System.out.println("Hello world");
}
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public String removeKdigits(String num, int k) {
if (k >= num.length()) {
return "0";
}
Stack<Character> stack = new Stack<>();
for (int i = 0; i < num.length(); i++) {
if (stack.isEmpty() || k == 0) {
stack.push(num.charAt(i));
} else {
if (num.charAt(i) < stack.peek() ) {
while (!stack.empty() && num.charAt(i) < stack.peek() && k > 0) {
stack.pop();
k--;
}
}
stack.push(num.charAt(i));
}
}
while (k > 0 ) {
stack.pop();
k--;
}
StringBuilder sb = new StringBuilder();
while (!stack.empty()) {
sb.append(stack.pop());
}
String ans = sb.reverse().toString();
if (ans.isEmpty()) {
return "0";
}
boolean startZero = ans.charAt(0) == '0';
if (!startZero) {
return ans;
}
for (int i = 1; i < ans.length(); i++) {
if (ans.charAt(i) != '0') {
return ans.substring(i);
}
}
return "0";
}
}
//leetcode submit region end(Prohibit modification and deletion)
}