请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
使用一个单调栈处理
第一个元素下标入栈,然后每次比较一下peek位置的元素和第i个元素,如果大就弹出,弹到小入栈,并记录res数组值
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
LinkedList stack = new LinkedList<>();
int[] res = new int[temperatures.length];
stack.push(0);
for (int i = 1; i < temperatures.length; i++){
while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]){
int temp = stack.pop();
res[temp] = i - temp;
}
stack.push(i);
}
return res;
}
}
给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。
请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。
nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。
理清楚逻辑,nums1记录一个哈希表,遍历nums2,使用单调栈,如果要加入的比栈顶大,就弹出,弹出之后其实就找到了栈顶这个元素在nums2中比他大的下一个元素,因为nums1是nums2的子集,所以这个元素在nums1中不一定有,要判断一下,确实有了再记录到res数组中
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
Map map = new HashMap<>();
for (int i = 0; i < nums1.length; i++){
map.put(nums1[i],i);//建立哈希表
}
LinkedList stack = new LinkedList<>();
int[] res = new int[nums1.length];
Arrays.fill(res,-1);//初始化为-1,最后单调栈中会剩余元素,默认res中对应位置为-1
stack.push(nums2[0]);
for (int i = 1; i < nums2.length; i++){
while (!stack.isEmpty() && nums2[i] > stack.peek()){
int temp = stack.pop();
if (map.containsKey(temp)){//要判断一下哈希表中是否有这个key
res[map.get(temp)] = nums2[i];//有的话才更新res数组
}
}
stack.push(nums2[i]);//别忘了循环结束要把元素加进来
}
return res;
}
}
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
和上一道题整体思路差不多,不需要建立哈希表,因为是同一个数组
主要是循环数组的处理,可以遍历两遍数组,注意使用取余运算
class Solution {
public int[] nextGreaterElements(int[] nums) {
int[] res = new int[nums.length];
Arrays.fill(res,-1);
LinkedList stack = new LinkedList<>();
stack.push(0);
for (int i = 1; i < 2 * nums.length; i++){
while (!stack.isEmpty() && nums[i % nums.length] > nums[stack.peek()]){
int temp = stack.pop();
res[temp] = nums[i % nums.length];
}
stack.push(i % nums.length);
}
return res;
}
}
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
方法一:暴力遍历
首先注意,第一个位置和最后一个位置不能装雨水
每个位置能装的雨水的量取决于,它左侧和右侧最大元素中更小的那个(木桶壁)
因此可以使用双层循环遍历,遍历数组,每一个位置都去找左侧和右侧最大的元素,求出这个位置能装雨水的量,然后相加
方法二:双指针优化
使用两个数组记录每个元素它左侧元素最大值和右侧元素最大值
这样可以把时间复杂度降到O(n)
方法三:单调栈
使用单调栈处理,一旦发现后一个元素比前一个大,说明出现了凹槽,则可能要装雨水
栈中pop的元素是要装雨水的位置
栈中再peek的元素是左侧的最大值(因为是单调栈)
这时遍历到的元素是右侧的墙壁,这时就考虑装雨水,面积是长×宽
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 heightL = height[i];
int heightR = height[i];
for (int j = i; j >= 0; j--){
heightL = Math.max(heightL,height[j]);//左侧最大元素
}
for (int j = i; j < height.length; j++){
heightR = Math.max(heightR,height[j]);//右侧最大元素
}
int temp = Math.min(heightL,heightR) - height[i];//这个位置装雨水量
if (temp > 0) sum += temp;//加和,注意判断是否大于0
}
return sum;
}
}
class Solution1 {
public int trap(int[] height) {
int sum = 0;
int[] heightL = new int[height.length];
int[] heightR = new int[height.length];
heightL[0] = height[0];
for (int i = 1; i < height.length; i++){
heightL[i] = Math.max(heightL[i - 1], height[i]);
}
heightR[height.length - 1] = height[height.length - 1];
for (int i = height.length - 2; i >= 0; i--){
heightR[i] = Math.max(heightR[i + 1], height[i]);
}
for (int i = 0; i < height.length; i++){
int temp = Math.min(heightL[i], heightR[i]) - height[i];
if (temp > 0) sum += temp;
}
return sum;
}
}
class Solution2 {
public int trap(int[] height) {
int sum = 0;
LinkedList stack = new LinkedList<>();
stack.add(0);
for (int i = 1; i < height.length; i++) {
if (height[i] < height[stack.peek()]) stack.push(i);
else if (height[i] == height[stack.peek()]) {
stack.pop();
stack.push(i);
} else {
while (!stack.isEmpty() && height[i] > height[stack.peek()]){
int mid = stack.pop();
if (!stack.isEmpty()){//这个地方要再判断一下,不然空指针
int left = stack.peek();
sum += (Math.min(height[left], height[i]) - height[mid]) * (i - left - 1);
}
}
stack.push(i);
}
}
return sum;
}
}
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
和上题思路类似
但注意这题如果元素递增,会输出零,考虑使用数组扩容的方式,在头尾加上两个0,保证一定会取出面积
class Solution {
public int largestRectangleArea(int[] heights) {
int res = 0;
LinkedList stack = new LinkedList<>();
int[] heightsNew = new int[heights.length + 2];
for (int i = 1; i <= heights.length; i++) {
heightsNew[i] = heights[i - 1];
}
stack.push(0);
for (int i = 1; i < heightsNew.length; i++) {
if (heightsNew[i] > heightsNew[stack.peek()]) stack.push(i);
else if (heightsNew[i] == heightsNew[stack.peek()]) {
stack.pop();
stack.push(i);
} else {
while (!stack.isEmpty() && heightsNew[i] < heightsNew[stack.peek()]){
int mid = stack.pop();
if (!stack.isEmpty()){
int left = stack.peek();
res = Math.max(res, (i - left - 1) * heightsNew[mid]);
}
}
stack.push(i);
}
}
return res;
}
}
从一月底到现在,50天的时间,完成了代码随想录一刷
除了个别比较难的题目,其他都自己手写了代码
接下来要继续进行二刷,五一前争取二刷完毕!
二刷目的是更熟悉题型,争取多写几种解法
每天抽出来2h时间,限时完成
慢慢算法路,才刚刚开始!
加油吧!
且视他人之疑目如盏盏鬼火,大胆地去走我的夜路。