题目描述:
小R最近遇到了一个数组问题。他有一个包含 N 个元素的数组,记作 a1, a2, ..., aN。
为了分析这个数组的特性,小R定义了两个函数 L(i) 和 R(i),并希望通过这两个函数来找到一些有趣的结论。
-
L(i) :表示满足以下条件的最大的
j值:j < i且a[j] > a[i]。- 如果找不到这样的
j,那么L(i) = 0。 - 如果有多个满足条件的
j,选择离i最近的那个。
-
R(i) :表示满足以下条件的最小的
k值:k > i且a[k] > a[i]。- 如果找不到这样的
k,那么R(i) = 0。 - 如果有多个满足条件的
k,选择离i最近的那个。
最终,小R定义 MAX(i) = L(i) * R(i),他想知道在 1 ≤ i ≤ N 的范围内,MAX(i) 的最大值是多少。
思路分析:
1. 理解问题需求:
- 对于每一个元素
a[i],我们需要找出它左边第一个大于它的元素(即L(i))以及右边第一个大于它的元素(即R(i))。 - 如果
L(i)和R(i)都存在,那么MAX(i) = L(i) * R(i);否则,MAX(i)为 0。 - 最终,我们的目标是找到所有
MAX(i)中的最大值。
2. 算法的实现步骤:
-
计算 L(i) :对于每个
i,我们可以通过从左到右扫描数组来找出左边第一个大于a[i]的元素。为了提高效率,可以使用一个栈来帮助快速查找。- 对于每个元素
a[i],从栈顶检查是否存在比a[i]大的元素。如果有,则更新L(i),如果没有,则将0作为结果。
- 对于每个元素
-
计算 R(i) :与计算
L(i)相似,但是这次我们是从右向左扫描数组,找出右边第一个大于a[i]的元素。 -
最终结果:对于每个
i,计算L(i) * R(i),更新最大值。
3. 时间复杂度分析:
L(i)和R(i)的计算都涉及到栈的使用,栈的操作时间复杂度是O(1),因此整个算法的时间复杂度是O(N),其中N是数组的大小。
Java代码实现:
import java.util.Stack;
public class Main {
public static int solution(int n, int[] array) {
// Edit your code here
int[] L = new int[n];
int[] R = new int[n];
// 栈用于计算L(i)
Stack<Integer> stackL = new Stack<>();
// 从左到右计算L(i)
for (int i = 0; i < n; i++) {
while (!stackL.isEmpty() && array[stackL.peek()] <= array[i]) {
stackL.pop();
}
L[i] = (stackL.isEmpty()) ? 0 : stackL.peek() + 1;
stackL.push(i);
}
// 栈用于计算R(i)
Stack<Integer> stackR = new Stack<>();
// 从右到左计算R(i)
for (int i = n - 1; i >= 0; i--) {
while (!stackR.isEmpty() && array[stackR.peek()] <= array[i]) {
stackR.pop();
}
R[i] = (stackR.isEmpty()) ? 0 : stackR.peek() + 1;
stackR.push(i);
}
// 计算MAX(i)并找出最大值
int maxProduct = 0;
for (int i = 0; i < n; i++) {
maxProduct = Math.max(maxProduct, L[i] * R[i]);
}
return maxProduct;
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(solution(5, new int[]{5, 4, 3, 4, 5}) == 8);
}
}
代码说明:
-
输入和初始化:
- 输入一个数组
array,并定义两个数组L和R来分别存储每个位置的L(i)和R(i)值。
- 输入一个数组
-
计算 L(i) :
- 使用一个栈
leftStack来存储索引。遍历数组,对于每个元素a[i],找到它左边第一个大于它的元素。 - 如果栈顶的元素小于等于
a[i],则弹出栈顶元素,继续查找。
- 使用一个栈
-
计算 R(i) :
- 使用类似的方法来计算右边第一个大于它的元素。这里的栈
rightStack存储的是索引,从右到左遍历数组。
- 使用类似的方法来计算右边第一个大于它的元素。这里的栈
-
计算 MAX(i) :
- 对每个位置
i,计算L(i) * R(i),并找出最大值。
- 对每个位置
总结:
- 本题的核心是如何高效计算每个位置
L(i)和R(i),利用栈的特性能够在O(N)的时间复杂度内完成。 - 通过两次栈的遍历(分别从左到右和从右到左),可以迅速找到每个元素左边和右边第一个大于它的元素,从而计算出
MAX(i)。