代码段的目的是计算一组整数中,每个元素左右的相邻元素中较大的那个元素的最大乘积。具体来说,代码使用两个一维数组 ( L ) 和 ( R ) 来存储与每个元素相关的值,从而计算出对于每个元素的值 ( MAX(i) = L(i) * R(i) )。下面是对代码的逐步解析:
代码解释:
-
初始化数组
L和R:int[] L = new int[n]; int[] R = new int[n]; for (int i = 0; i < n; i++) { L[i] = 0; R[i] = 0; }这里创建了长度为 ( n ) 的数组
L和R,并将它们的所有值初始化为 0。这两个数组用于存储每个元素的左边和右边的值的索引。 -
计算
L(i):Stack<Integer> stack = new Stack<>(); for (int i = 0; i < n; i++) { while (!stack.isEmpty() && array[stack.peek()] <= array[i]) { stack.pop(); } L[i] = stack.isEmpty() ? 0 : stack.peek() + 1; stack.push(i); }- 使用单调栈的方式从左到右遍历数组。
- 当前元素
array[i]的左边元素(即L(i))被设置为最近的比array[i]大的元素的索引。 - 如果栈为空,说明
array[i]左边没有比它大的元素,则L[i]为 0。 - 最终
L数组对于每个元素i存储了一个有效的索引,指向它左边第一个大于array[i]的元素。
-
计算
R(i):stack.clear(); for (int i = n - 1; i >= 0; i--) { while (!stack.isEmpty() && array[stack.peek()] <= array[i]) { stack.pop(); } R[i] = stack.isEmpty() ? 0 : stack.peek() + 1; stack.push(i); }- 这部分的逻辑与计算
L(i)部分类似,只不过是从右到左遍历数组,计算每个元素右边的最近较大的元素。 - 使用清空栈的方法,确保在这次计算中使用一个新的栈。
- 这部分的逻辑与计算
-
计算最大乘积:
int maxProduct = 0; for (int i = 0; i < n; i++) { maxProduct = Math.max(maxProduct, L[i] * R[i]); } return maxProduct;- 最后,迭代数组,计算每个元素的乘积 ( L(i) * R(i) ),同时更新当前最大的乘积。
总结:
该算法有效使用了单调栈来减少复杂度,从而使得在计算每个元素左右第一个较大元素时避免了重复遍历,可以在 ( O(n) ) 时间复杂度内完成计算。这对于大数组的情况特别高效。
这段代码的目的是计算一组整数中,每个元素左右的相邻元素中较大的那个元素的最大乘积。具体来说,代码通过使用单调栈和两个辅助数组 ( L ) 和 ( R ) 来存储每个元素左右最近的较大元素的索引,从而计算出最大乘积。下面是对代码的详细原理解析。
原理解析
-
初始化数组
L和R:L[i]用于存储数组中第i个元素左边第一个大于array[i]的元素的索引(如果不存在则为 0)。R[i]用于存储数组中第i个元素右边第一个大于array[i]的元素的索引(同样,如果不存在则为 0)。- 初始化这两个数组为 0,表示尚未找到任何较大的元素。
-
计算
L(i):Stack<Integer> stack = new Stack<>(); for (int i = 0; i < n; i++) { while (!stack.isEmpty() && array[stack.peek()] <= array[i]) { stack.pop(); } L[i] = stack.isEmpty() ? 0 : stack.peek() + 1; stack.push(i); }- 使用单调栈从左到右遍历数组。
- 对于每个元素
array[i],将栈中所有小于等于array[i]的索引弹出,保持栈中的元素是递减的。 - 如果栈为空,表示没有找到比
array[i]大的元素,L[i]设置为 0。否则,L[i]设置为栈顶元素的索引加 1(因为我们需要的是索引)。 - 最后,将当前元素的索引
i压入栈中,准备处理后续元素。
-
计算
R(i):stack.clear(); for (int i = n - 1; i >= 0; i--) { while (!stack.isEmpty() && array[stack.peek()] <= array[i]) { stack.pop(); } R[i] = stack.isEmpty() ? 0 : stack.peek() + 1; stack.push(i); }- 这部分逻辑与计算
L(i)类似,但从右到左遍历数组,计算每个元素右边的最近较大的元素。 - 清空栈以确保可以重新使用,避免干扰。
- 这部分逻辑与计算
-
计算最大乘积:
int maxProduct = 0; for (int i = 0; i < n; i++) { maxProduct = Math.max(maxProduct, L[i] * R[i]); } return maxProduct;- 遍历
L和R数组,计算每个元素的乘积 ( L(i) \times R(i) )。 - 更新
maxProduct为当前计算得到的最大值。
- 遍历
整体复杂度
- 时间复杂度:O(n),因为每个元素最多被压入和弹出栈一次。
- 空间复杂度:O(n),用于存储
L和R数组以及栈。
总结
该算法通过利用单调栈的特性,避免了重复遍历数组的必要性,从而高效地计算每个元素左右第一个较大元素的索引,并最终得出最大乘积。这种方法特别适合处理大规模数据,能够在保持线性时间复杂度的同时有效解决问题。