网站 公司,集团门户网站建设策划,湖南网站建设公司 地址磐石网络,交钱做网站对方拿了钱不做该怎么办503.下一个更大元素II
题目要求#xff1a;
给定一个循环数组#xff08;最后一个元素的下一个元素是数组的第一个元素#xff09;#xff0c;输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序#xff0c;这个数字之后的第一个比它更大的数
给定一个循环数组最后一个元素的下一个元素是数组的第一个元素输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序这个数字之后的第一个比它更大的数这意味着你应该循环地搜索它的下一个更大的数。如果不存在则输出 -1。
示例 1:
输入: [1,2,1]输出: [2,-1,2]解释: 第一个 1 的下一个更大的数是 2数字 2 找不到下一个更大的数第二个 1 的下一个最大的数需要循环搜索结果也是 2。
思路
可以选择扩充nums数组或者其实也可以不扩充nums而是在遍历的过程中模拟走了两边nums。
class Solution {
public:vectorint nextGreaterElements(vectorint nums) {vectorint result(nums.size(), -1);if (nums.size() 0) return result;stackint st;st.push(0);for (int i 1; i nums.size() * 2; i) {if (nums[i % nums.size()] nums[st.top()]) st.push(i % nums.size());else if (nums[i % nums.size()] nums[st.top()]) st.push(i % nums.size());else {while (!st.empty() nums[i % nums.size()] nums[st.top()]) {result[st.top()] nums[i % nums.size()];st.pop();}st.push(i % nums.size());}}return result;}
};
42. 接雨水
题目要求给定 n 个非负整数表示每个宽度为 1 的柱子的高度图计算按此排列的柱子下雨之后能接多少雨水。 输入height [0,1,0,2,1,0,1,3,2,1,2,1]输出6解释上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图在这种情况下可以接 6 个单位的雨水蓝色部分表示雨水。
示例 2
输入height [4,2,0,3,2,5]输出9
思路
本题暴力解法也是也是使用双指针。
首先要明确要按照行来计算还是按照列来计算。
按照行来计算如图 按照列来计算如图 一些同学在实现的时候很容易一会按照行来计算一会按照列来计算这样就会越写越乱。
我个人倾向于按照列来计算比较容易理解接下来看一下按照列如何计算。
首先如果按照列来计算的话宽度一定是1了我们再把每一列的雨水的高度求出来就可以了。
可以看出每一列雨水的高度取决于该列 左侧最高的柱子和右侧最高的柱子中最矮的那个柱子的高度。
这句话可以有点绕来举一个理解例如求列4的雨水高度如图 列4 左侧最高的柱子是列3高度为2以下用lHeight表示。
列4 右侧最高的柱子是列7高度为3以下用rHeight表示。
列4 柱子的高度为1以下用height表示
那么列4的雨水高度为 列3和列7的高度最小值减列4高度即 min(lHeight, rHeight) - height。
列4的雨水高度求出来了宽度为1相乘就是列4的雨水体积了。
此时求出了列4的雨水体积。
一样的方法只要从头遍历一遍所有的列然后求出每一列雨水的体积相加之后就是总雨水的体积了。
首先从头遍历所有的列并且要注意第一个柱子和最后一个柱子不接雨水代码如下
for (int i 0; i height.size(); i) {// 第一个柱子和最后一个柱子不接雨水if (i 0 || i height.size() - 1) continue;
}
在for循环中求左右两边最高柱子代码如下
int rHeight height[i]; // 记录右边柱子的最高高度
int lHeight height[i]; // 记录左边柱子的最高高度
for (int r i 1; r height.size(); r) {if (height[r] rHeight) rHeight height[r];
}
for (int l i - 1; l 0; l--) {if (height[l] lHeight) lHeight height[l];
}
最后计算该列的雨水高度代码如下
int h min(lHeight, rHeight) - height[i];
if (h 0) sum h; // 注意只有h大于零的时候在统计到总和中
整体代码如下
class Solution {
public:int trap(vectorint height) {int sum 0;for (int i 0; i height.size(); i) {// 第一个柱子和最后一个柱子不接雨水if (i 0 || i height.size() - 1) continue;int rHeight height[i]; // 记录右边柱子的最高高度int lHeight height[i]; // 记录左边柱子的最高高度for (int r i 1; r height.size(); r) {if (height[r] rHeight) rHeight height[r];}for (int l i - 1; l 0; l--) {if (height[l] lHeight) lHeight height[l];}int h min(lHeight, rHeight) - height[i];if (h 0) sum h;}return sum;}
};
因为每次遍历列的时候还要向两边寻找最高的列所以时间复杂度为O(n^2)空间复杂度为O(1)。
力扣后面修改了后台测试数据所以以上暴力解法超时了。
单调栈解法
单调栈就是保持栈内元素有序。通常是一维数组要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置此时我们就要想到可以用单调栈了。
而接雨水这道题目我们正需要寻找一个元素右边最大元素以及左边最大元素来计算雨水面积。
准备工作
那么本题使用单调栈有如下几个问题
1. 首先单调栈是按照行方向来计算雨水如图 知道这一点后面的就可以理解了。
2. 使用单调栈内元素的顺序
从大到小还是从小到大呢
从栈头元素从栈头弹出到栈底的顺序应该是从小到大的顺序。
因为一旦发现添加的柱子高度大于栈头元素了此时就出现凹槽了栈头元素就是凹槽底部的柱子栈头第二个元素就是凹槽左边的柱子而添加的元素就是凹槽右边的柱子。
如图 3. 遇到相同高度的柱子怎么办。
遇到相同的元素更新栈内下标就是将栈里元素旧下标弹出将新元素新下标加入栈中。
例如 5 5 1 3 这种情况。如果添加第二个5的时候就应该将第一个5的下标弹出把第二个5添加到栈中。
因为我们要求宽度的时候 如果遇到相同高度的柱子需要使用最右边的柱子来计算宽度。
如图所示 4. 栈里要保存什么数值
使用单调栈也是通过 长 * 宽 来计算雨水面积的。
长就是通过柱子的高度来计算宽是通过柱子之间的下标来计算
那么栈里有没有必要存一个pairint, int类型的元素保存柱子的高度和下标呢。
其实不用栈里就存放下标就行想要知道对应的高度通过height[stack.top()] 就知道弹出的下标对应的高度了。
所以栈的定义如下
stackint st; // 存着下标计算的时候用下标对应的柱子高度
明确了如上几点我们再来看处理逻辑。
单调栈处理逻辑
以下逻辑主要就是三种情况
情况一当前遍历的元素柱子高度小于栈顶元素的高度 height[i] height[st.top()]情况二当前遍历的元素柱子高度等于栈顶元素的高度 height[i] height[st.top()]情况三当前遍历的元素柱子高度大于栈顶元素的高度 height[i] height[st.top()]
先将下标0的柱子加入到栈中st.push(0);。 栈中存放我们遍历过的元素所以先将下标0加进来。
然后开始从下标1开始遍历所有的柱子for (int i 1; i height.size(); i)。
如果当前遍历的元素柱子高度小于栈顶元素的高度就把这个元素加入栈中因为栈里本来就要保持从小到大的顺序从栈头到栈底。
代码如下
if (height[i] height[st.top()]) st.push(i);
如果当前遍历的元素柱子高度等于栈顶元素的高度要跟更新栈顶元素因为遇到相相同高度的柱子需要使用最右边的柱子来计算宽度。
代码如下
if (height[i] height[st.top()]) { // 例如 5 5 1 7 这种情况st.pop();st.push(i);
}
如果当前遍历的元素柱子高度大于栈顶元素的高度此时就出现凹槽了如图所示 取栈顶元素将栈顶元素弹出这个就是凹槽的底部也就是中间位置下标记为mid对应的高度为height[mid]就是图中的高度1。
此时的栈顶元素st.top()就是凹槽的左边位置下标为st.top()对应的高度为height[st.top()]就是图中的高度2。
当前遍历的元素i就是凹槽右边的位置下标为i对应的高度为height[i]就是图中的高度3。
此时大家应该可以发现其实就是栈顶和栈顶的下一个元素以及要入栈的元素三个元素来接水
那么雨水高度是 min(凹槽左边高度, 凹槽右边高度) - 凹槽底部高度代码为int h min(height[st.top()], height[i]) - height[mid];
雨水的宽度是 凹槽右边的下标 - 凹槽左边的下标 - 1因为只求中间宽度代码为int w i - st.top() - 1 ;
当前凹槽雨水的体积就是h * w。
求当前凹槽雨水的体积代码如下
while (!st.empty() height[i] height[st.top()]) { // 注意这里是while持续跟新栈顶元素int mid st.top();st.pop();if (!st.empty()) {int h min(height[st.top()], height[i]) - height[mid];int w i - st.top() - 1; // 注意减一只求中间宽度sum h * w;}
}
class Solution {
public:int trap(vectorint height) {if (height.size() 2) return 0;stackint st;st.push(0);int sum 0;for (int i 1; i height.size(); i) {if (height[i] height[st.top()]) {st.push(i);} else if (height[i] height[st.top()]) {st.pop();st.push(i);} else {while (!st.empty() height[i] height[st.top()]) {int mid st.top();st.pop();if (!st.empty()) {int h min(height[st.top()], height[i]) - height[mid];int w i - st.top() - 1;sum h * w;}}st.push(i);}}return sum;}
};