博主个人博客网站:文客
这个系列主要记录在力扣刷题的总结和问题
如果你想每天和我一起刷题,可以关注一下我的个人博客网站:文客,我会每天在这里更新技术文章和面试题,也会及时收到大家的评论与留言,欢迎各位大佬来交流!
739. 每日温度
给定一个整数数组 temperatures
,表示每天的温度,返回一个数组 answer
,其中 answer[i]
是指在第 i
天之后,才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0
来代替。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
示例 2:
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
示例 3:
输入: temperatures = [30,60,90]
输出: [1,1,0]
思路:
使用单调栈,我们在程序中维护一个栈,这个栈存储温度数组的下标,而且栈顶到栈尾是递增的,当遇到比栈顶大的元素时就代表遇见了第一个更高的温度,根据下标差值计算天数即可,将结果存储在res数组中
题解:
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int[] res = new int[temperatures.length];
Stack<Integer> stack = new Stack<>();
stack.push(0);
for(int i = 1; i < temperatures.length; i++){
if(temperatures[i] <= temperatures[stack.peek()]){
stack.push(i);
} else {
while(!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]){
res[stack.peek()] = i - stack.peek();
stack.pop();
}
stack.push(i);
}
}
return res;
}
}
496. 下一个更大元素 I
nums1
中数字 x
的 下一个更大元素 是指 x
在 nums2
中对应位置 右侧 的 第一个 比 x
大的元素。
给你两个 没有重复元素 的数组 nums1
和 nums2
,下标从 0 开始计数,其中nums1
是 nums2
的子集。
对于每个 0 <= i < nums1.length
,找出满足 nums1[i] == nums2[j]
的下标 j
,并且在 nums2
确定 nums2[j]
的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1
。
返回一个长度为 nums1.length
的数组 ans
作为答案,满足 ans[i]
是如上所述的 下一个更大元素 。
示例 1:
输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
- 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
- 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
示例 2:
输入:nums1 = [2,4], nums2 = [1,2,3,4].
输出:[3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 2 ,用加粗斜体标识,nums2 = [1,2,3,4]。下一个更大元素是 3 。
- 4 ,用加粗斜体标识,nums2 = [1,2,3,4]。不存在下一个更大元素,所以答案是 -1 。
思路:
维护一个单调栈,因为nums1是nums2的子集,所以我们遍历nums2,利用单调栈的特性求出nums2中每个元素的下一个更大元素,用map存储结果,最后再遍历nums1赋予结果
题解:
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int[] res = new int[nums1.length];
Stack<Integer> stack = new Stack<>();
HashMap<Integer,Integer> map = new HashMap<>();
stack.push(0);
for(int i = 1; i < nums2.length; i++){
if(nums2[i] < nums2[stack.peek()]){
stack.push(i);
} else {
while(!stack.isEmpty() && nums2[i] > nums2[stack.peek()]){
map.put(nums2[stack.peek()],nums2[i]);
stack.pop();
}
stack.push(i);
}
}
for(int i = 0; i < nums1.length; i++){
res[i] = map.getOrDefault(nums1[i],-1);
}
return res;
}
}
503. 下一个更大元素 II
给定一个循环数组 nums
( nums[nums.length - 1]
的下一个元素是 nums[0]
),返回 nums
中每个元素的 下一个更大元素 。
数字 x
的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1
。
示例 1:
输入: nums = [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
示例 2:
输入: nums = [1,2,3,4,3]
输出: [2,3,4,-1,4]
思路:
循环数组一般就开二倍长度的数组,收尾相接,然后维护一个单调栈即可
题解:
class Solution {
public int[] nextGreaterElements(int[] nums) {
int[] res = new int[nums.length];
Stack<Integer> stack = new Stack<>();
Arrays.fill(res,-1);
stack.push(0);
for(int i = 1; i < 2 * nums.length; i++){
if(nums[i % nums.length] <= nums[stack.peek()]){
stack.push(i % nums.length);
} else {
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. 接雨水
给定 n
个非负整数表示每个宽度为 1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 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(双指针):
遍历height数组,每遍历到一个元素时,分别向左向右寻找最高的高度,然后用左右最高高度的最小值减去当前高度,就是当前高度可以接的雨水。
题解1(双指针):
class Solution {
public int trap(int[] height) {
int res = 0;
for(int i = 0; i < height.length; i++){
int lHeight = height[i];
int rHeight = height[i];
for(int l = i - 1; l >= 0; l--){
if(height[l] > lHeight){
lHeight = height[l];
}
}
for(int r = i + 1; r < height.length; r++){
if(height[r] > rHeight){
rHeight = height[r];
}
}
int t = Math.min(rHeight,lHeight) - height[i];
res += t;
}
return res;
}
}
思路2(动态规划):
动态规划是双指针解法的优化版本,也是对每个高度求出左边最高和右边最高,后面的思路都是一样的
题解2(动态规划):
class Solution {
public int trap(int[] height) {
int res = 0;
int[] dp1 = new int[height.length];
int[] dp2 = new int[height.length];
dp1[0] = height[0];
for(int i = 1; i < height.length; i++){
dp1[i] = Math.max(dp1[i - 1], height[i]);
}
dp2[height.length - 1] = height[height.length - 1];
for(int i = height.length - 2; i >= 0; i--){
dp2[i] = Math.max(dp2[i + 1], height[i]);
}
for(int i = 0; i < height.length; i++){
res += Math.min(dp1[i],dp2[i]) - height[i];
}
return res;
}
}
思路3(单调栈):
维护一个单调栈,这个栈从栈头到栈尾是单调递增的,这样遇到更大的高度时,才会出现凹槽。
题解3(单调栈):
class Solution {
public int trap(int[] height) {
int res = 0;
Stack<Integer> stack = new Stack<>();
int[] temp = new int[height.length + 2];
temp[0] = 0;
temp[temp.length - 1] = 0;
for(int i = 1; i < temp.length - 1; i++){
temp[i] = height[i - 1];
}
stack.push(0);
for(int i = 1; i < temp.length; i++){
if(temp[i] < temp[stack.peek()]){
stack.push(i);
} else if(temp[i] == temp[stack.peek()]){
stack.push(i);
} else {
while(!stack.isEmpty() && temp[i] > temp[stack.peek()]){
int mid = stack.pop();
if(!stack.isEmpty()){
int left = stack.peek();
int t = (Math.min(temp[i],temp[left]) - temp[mid]) * (i - left - 1);
res += (t > 0) ? t : 0;
}
}
stack.push(i);
}
}
return res;
}
}
84. 柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例 1:
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
示例 2:
输入: heights = [2,4]
输出: 4
思路:
维护一个单调栈,栈头到栈尾是单调递减的,遇到下一个更小的元素就可以计算当前的最大面积
题解:
class Solution {
public int largestRectangleArea(int[] heights) {
int largestArea = 0;
int[] temp = new int[heights.length + 2];
temp[0] = 0;
temp[temp.length - 1] = 0;
for(int i = 1; i < temp.length - 1; i++){
temp[i] = heights[i - 1];
}
Stack<Integer> stack = new Stack<>();
stack.push(0);
for(int i = 1; i < temp.length; i++){
while(!stack.isEmpty() && temp[i] < temp[stack.peek()]){
int h = temp[stack.pop()];
largestArea = Math.max(largestArea,h * (i - stack.peek() - 1));
}
stack.push(i);
}
return largestArea;
}
}