单调栈模型
单调栈本质: 及时去掉无用数据, 保证栈中数据有序。
单调栈的思考方法,假设我们要找寻右侧第一个大于当前数字的数,就要将<=当前数的元素出栈。
当拿到一个问题时,要大的,剔除小的;要小的,剔除大的。
模板题:
class Solution: def dailyTemperatures(self, temperatures: List[int]) -> List[int]: n = len(temperatures) stk = [] ans = [0] * n for i in range(n - 1, -1, -1): t = temperatures[i] while stk and t >= temperatures[stk[-1]]: stk.pop() if stk: ans[i] = stk[-1] - i stk.append(i) return ans
class Solution: def dailyTemperatures(self, temperatures: List[int]) -> List[int]: n = len(temperatures) stk = [] ans = [0] * n for i, t in enumerate(temperatures): while stk and temperatures[stk[-1]] < t: j = stk.pop() ans[j] = i - j stk.append(i) return ans
数组的循环操作可以用模运算来实现
class Solution: def nextGreaterElements(self, nums: List[int]) -> List[int]: n = len(nums) stk = [] ans = [-1] * n for i in range(n * 2): while stk and nums[stk[-1]] < nums[i % n]: j = stk.pop() ans[j] = nums[i % n] stk.append(i % n) return ans
class Solution: def nextGreaterElements(self, nums: List[int]) -> List[int]: n = len(nums) stk = [] ans = [-1] * n for i in range(n * 2 - 1, -1, -1): while stk and nums[stk[-1]] <= nums[i % n]: stk.pop() if stk: ans[i % n] = nums[stk[-1]] stk.append(i % n) return ans
class Solution: def trap(self, height: List[int]) -> int: n = len(height) stk = [] res = 0 for i, val in enumerate(height): while stk and height[stk[-1]] <= val: bottom_h = height[stk.pop()] if not stk: break left = stk[-1] dh = min(height[left], val) - bottom_h res += dh * (i - left - 1) stk.append(i) return res
class Solution { public: int numberOfWeakCharacters(vector<vector<int>>& properties) { sort(properties.begin(), properties.end(), [&](auto &a, auto &b) { return a[0] == b[0] ? a[1] > b[1]: a[0] < b[0]; }); int n = properties.size(); stack<int> stk; int res = 0; for(int i = 0; i < n; i ++ ) { while(stk.size() && properties[i][1] > properties[stk.top()][1]) { stk.pop(); res ++ ; } stk.push(i); } return res; } };
class Solution: def numberOfWeakCharacters(self, properties: List[List[int]]) -> int: n = len(properties) stk = [] res = 0 def cmp(a: tuple): return a[0], -a[1] properties.sort(key=cmp) for i in range(n): while stk and properties[stk[-1]][1] < properties[i][1]: stk.pop() res += 1 stk.append(i) return res
双单调栈
我们的单调栈每次回向外部弹出一个一个元素,在本题中,我们要用到这些被弹出的元素。
这些被弹出的元素有一个性质,就是他们的某一侧的最近的最值已经被找到了,那么这个题要找第二个比它大的,我们就在用一个单调栈将第一个单调栈弹出的数据弹出来,那么这个单调栈就可以统计右边第二大的数据了。
class Solution: def secondGreaterElement(self, nums: List[int]) -> List[int]: n = len(nums) s = [] t = [] ans = [-1] * n for i, x in enumerate(nums): while t and nums[t[-1]] < x: ans[t.pop()] = x j = len(s) - 1 while j >= 0 and nums[s[j]] < x: j -= 1 t += s[j + 1:] del s[j + 1:] s.append(i) return ans