每个元素为最大值的最大范围
难度:
标签:
题目描述
代码结果
运行时间: 164 ms, 内存: 33.3 MB
/*
* Leetcode 2832: 每个元素为最大值的最大范围
*
* 题目思路:
* 给定一个数组,要求找到每个元素在数组中作为最大值的最大范围。也就是说,
* 对于数组中的每个元素,找到包含它且它是最大值的最长子数组范围。
*
* 方法:
* 1. 我们可以使用单调栈来解决这个问题。
* 2. 先从左到右遍历数组,找到每个元素左侧第一个比它大的元素的位置。
* 3. 再从右到左遍历数组,找到每个元素右侧第一个比它大的元素的位置。
* 4. 通过左侧和右侧第一个比它大的元素的位置,可以确定该元素为最大值的最大范围。
*/
import java.util.*;
import java.util.stream.*;
public class MaxRangeForEachElementStream {
public int[][] maxRange(int[] nums) {
int n = nums.length;
int[] left = new int[n];
int[] right = new int[n];
Deque<Integer> stack = new ArrayDeque<>();
// 找到每个元素左侧第一个比它大的元素的位置
IntStream.range(0, n).forEach(i -> {
while (!stack.isEmpty() && nums[stack.peek()] <= nums[i]) {
stack.pop();
}
left[i] = stack.isEmpty() ? -1 : stack.peek();
stack.push(i);
});
stack.clear(); // 清空栈用于下一次遍历
// 找到每个元素右侧第一个比它大的元素的位置
IntStream.iterate(n - 1, i -> i >= 0, i -> i - 1).forEach(i -> {
while (!stack.isEmpty() && nums[stack.peek()] <= nums[i]) {
stack.pop();
}
right[i] = stack.isEmpty() ? n : stack.peek();
stack.push(i);
});
// 计算每个元素为最大值的最大范围
return IntStream.range(0, n).mapToObj(i -> new int[]{left[i] + 1, right[i] - 1}).toArray(int[][]::new);
}
}
解释
方法:
此题解的核心思路是利用一个单调递减栈来寻找每个元素作为最大值时的最大范围。遍历输入数组,对于每个元素,如果当前元素大于栈顶元素,则栈顶元素无法继续维持其为最大值的状态,需要从栈中移除,并更新结果数组中该元素的最大范围。如果栈为空,则表示当前元素左边没有更大的元素,其范围可以扩展到数组起始;如果栈不为空,则当前元素的范围是从栈顶元素的下一个位置到当前元素的位置。最后,遍历结束后,栈中剩余的元素表示它们的范围可以扩展到数组末尾。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么选择使用单调递减栈而不是其他类型的数据结构来解决这个问题?
▷🦆
在弹出栈顶元素时,你是如何确定该元素的最大范围的?具体的计算逻辑是什么?
▷🦆
如果数组中存在重复元素会如何影响栈的操作和最终的输出结果?
▷🦆
在算法的最后处理栈中剩余元素时,为什么更新范围至数组末尾的计算公式是 `n - stack[-1] - 1`?
▷