42. 接雨水
参考
思路1: 暴力解法
- 找每个柱子的左右高度
- 超时 O(N^2)
思路2: 双指针优化
class Solution {
public:int trap(vector<int>& height) {vector<int> lheight(height.size(), 0);vector<int> rheight(height.size(), 0);lheight[0] = height[0];for (int i = 1; i < height.size(); i++) {lheight[i] = max(lheight[i - 1], height[i]);}rheight[height.size() - 1] = height[height.size() - 1];for (int i = height.size() - 2; i >= 0; i--) {rheight[i] = max(rheight[i + 1], height[i]);}int res = 0;for (int i = 0; i < height.size(); i++) {if (i == 0 || i == height.size() - 1) continue;int min_val = min(lheight[i], rheight[i]);if (min_val - height[i] > 0) res += min_val - height[i];}return res;}
};
思路3: 单调栈
class Solution {
public:int trap(vector<int>& height) {int res = 0;stack<int> mystack;mystack.push(0);for (int i = 1; i < height.size(); i++) {if (height[i] < height[mystack.top()]) {mystack.push(i);} else if (height[i] == height[mystack.top()]) {mystack.push(i);} else {while (!mystack.empty() && height[i] >= height[mystack.top()]) {int right = i;int mid = mystack.top();mystack.pop();if (mystack.empty()) break;//元素数量不满足时, 无需回退上一步的pop操作, 放心舍弃元素(构不成封闭区间)int left = mystack.top();int w = right - left - 1;res += (min(height[left], height[right]) - height[mid]) * w;}mystack.push(i);}}return res;}
};
//对比: 细节处理存在问题, 虽然能通过, 实际上并不是单调栈(首元素的影响)
while (mystack.size() > 1 && height[i] >= height[mystack.top()]) {int right = i;int mid = mystack.top();mystack.pop();int left = mystack.top();int w = right - left - 1;if (min(height[left], height[right]) - height[mid] > 0)res += (min(height[left], height[right]) - height[mid]) * w;
}
84.柱状图中最大的矩形
思路: 单调栈
和接雨水相似, 区别在栈内元素轻的沉底
首插入0避免出现栈内元素不满足2的情况(如 3 1 2)
尾插入0避免出现一直满足栈条件而无法收获结果的情况(如 2 3 4 5)
class Solution {
public:int largestRectangleArea(vector<int>& heights) {heights.insert(heights.begin(), 0);heights.push_back(0);stack<int> mystask;mystask.push(0);int res = 0;for (int i = 1; i < heights.size(); i++) {if (heights[i] > heights[mystask.top()]) {mystask.push(i);} else if (heights[i] == heights[mystask.top()]) {mystask.push(i);} else {while (!mystask.empty() &&heights[i] < heights[mystask.top()]) {int right = i;int mid = mystask.top();mystask.pop();if (!mystask.empty()) {int left = mystask.top();int tem = (right - left - 1) * heights[mid];res = max(res, tem);}}mystask.push(i);}}return res;}
};
思路: 双指针
实现方式不同, 此处存放的是下标索引
class Solution {
public:int largestRectangleArea(vector<int>& heights) {int res = 0;vector<int> L_index(heights.size());vector<int> R_index(heights.size());for (int i = 0; i < heights.size(); i++) {int t = i;while (t > 0 && heights[t - 1] >= heights[i]) t = L_index[t - 1];//若改为 t--则会超时L_index[i] = t;}for (int i = heights.size() - 1; i >= 0; i--) {int t = i;while (t + 1 < heights.size() && heights[i] <= heights[t + 1]) t = R_index[t + 1];R_index[i] = t;}for (int i = 0; i < heights.size(); i++) {int W = R_index[i] - L_index[i] + 1;int tem = W * heights[i];res = max(res, tem);}return res;}
};