力扣503.下一个更大元素2
题目链接:https://leetcode.cn/problems/next-greater-element-ii/
思路
本题和每日温度很像,需要思考的就是如何处理循环数组。其实只要遍历两遍nums数组就可以了。此时数组下标就应该是i % nums.length
栈里还是存的下标,方便存入res数组。
完整代码
class Solution {
public int[] nextGreaterElements(int[] nums) {
int[] res = new int[nums.length];
Arrays.fill(res,-1);
Deque<Integer> stack = new LinkedList<>();
for (int i = 0; i < nums.length * 2; i++) {
while (!stack.isEmpty() && nums[i % nums.length] > nums[stack.peek()]){
res[stack.peek()] = nums[i % nums.length];
stack.pop();
}
stack.push(i % nums.length);
}
return res;
}
}
力扣42.接雨水
题目链接:https://leetcode.cn/problems/trapping-rain-water/
思路
双指针版
按列来计算,遍历所有列,将每列的雨水相加,就是接到的雨水总量。
那么计算每个列时,要找到这个列左侧的最高柱子,这个列右侧的最高柱子,取他俩的最小值再减去当前这个列(柱子)的高度。
在这个列接到雨水为正值时,再累加进去。
单调栈版
按行来计算。
栈里存放数组下标,维护一个栈顶到栈底递增的单调栈。
(1)当遍历元素小于等于栈顶元素时,压入栈中。
(2)当遍历元素大于栈顶元素时,说明出现凹槽,开始操作:
雨水体积是长*宽。为直观表现,栈内元素为柱子高度,实际上应该是下标。例如栈中元素是[6,5],遍历元素是7,此时的长为:min(6,7)-5;宽为:当前遍历元素下标-栈顶第二个元素下标-1,放在例子中即为2-0-1=1。
完整代码
双指针版
class Solution {
public int trap(int[] height) {
int sum = 0;
for (int i = 0; i < height.length; i++) {
if(i == 0 || i == height.length-1) continue;
int rheight = height[i];
int lheight = height[i];
for (int r = i+1; r < height.length; r++) {
rheight = Math.max(rheight,height[r]);
}
for (int l = i-1; l >= 0; l--) {
lheight = Math.max(lheight,height[l]);
}
int v = Math.min(lheight,rheight) - height[i];
if(v > 0) sum += v;
}
return sum;
}
}
单调栈版
class Solution {
public int trap(int[] height) {
Stack<Integer> st = new Stack<>(); // 存着下标,计算的时候用下标对应的柱子高度
st.push(0);
int sum = 0;
for (int i = 1; i < height.length; i++) {
if (height[i] < height[st.peek()]) { // 情况一
st.push(i);
} if (height[i] == height[st.peek()]) { // 情况二
st.pop(); // 其实这一句可以不加,效果是一样的,但处理相同的情况的思路却变了。
st.push(i);
} else { // 情况三
while (!st.isEmpty() && height[i] > height[st.peek()]) { // 注意这里是while
int mid = st.peek();
st.pop();
if (!st.isEmpty()) {
int h = Math.min(height[st.peek()], height[i]) - height[mid];
int w = i - st.peek() - 1; // 注意减一,只求中间宽度
sum += h * w;
}
}
st.push(i);
}
}
return sum;
}
}