返回
JavaScript剖析 LeetCode 84:柱状图中最大的矩形
前端
2023-11-06 15:20:40
探索柱状图中的最大矩形
导读
想像一座座鳞次栉比的大厦排列成壮观的柱状图,每一栋大厦的高度由一个非负整数表示。在这片城市森林中,你打算建造一座面积尽可能大的矩形建筑。那么,你将如何规划它的蓝图?
本文将深入探究这一引人入胜的编程难题,即在柱状图中寻找最大矩形面积。我们将从直观的暴力法入手,逐步揭秘更优雅高效的双指针算法,让你领略算法之美。
暴力出击:双循环法
首先,我们祭出最直白的暴力法:双循环遍历。这种方法简单易懂,但代价是时间复杂度较高。算法的精髓在于,对于每一列,我们以该列的高度作为起点,逐一扩展矩形的宽度,计算所有可能矩形的面积,并从中选出最大的一个。
代码示例:
function largestRectangleArea1(heights) {
let maxArea = 0;
for (let i = 0; i < heights.length; i++) {
for (let j = i; j < heights.length; j++) {
const currentArea = heights[i] * (j - i + 1);
maxArea = Math.max(maxArea, currentArea);
}
}
return maxArea;
}
双指针法:优雅的舞步
接下来,我们将介绍双指针法,它在时间复杂度上更胜一筹。算法的巧妙之处在于使用两个指针分别从左右向中心收缩。我们首先设置左右指针在柱状图的两端,然后不断向内移动指针,直到它们相遇。
如何移动指针?
- 如果左指针指向的高度比右指针低,则我们移动左指针,因为此时向左扩展可以增加矩形高度。
- 如果右指针指向的高度比左指针低,则我们移动右指针,因为向右扩展可以增加矩形宽度。
- 在移动指针的同时,我们计算当前高度对应的矩形面积,并将其与最大面积比较,保留更大的一个。
代码示例:
function largestRectangleArea2(heights) {
let maxArea = 0;
let left = 0;
let right = heights.length - 1;
while (left <= right) {
const currentArea = Math.min(heights[left], heights[right]) * (right - left + 1);
maxArea = Math.max(maxArea, currentArea);
if (heights[left] < heights[right]) {
left++;
} else {
right--;
}
}
return maxArea;
}
效率对比
双循环法的复杂度为 O(n^2),其中 n 是柱状图的长度。双指针法的复杂度则为 O(n),大大降低了时间消耗。
进阶技巧
为了进一步优化算法,我们可以引入一些额外的技巧:
- 优化暴力法: 预先计算每个高度的最大宽度,从而减少后续枚举的范围。
- 单调栈: 使用栈来存储已经访问过的高度,避免重复计算。
常见问题解答
- 为什么双指针法比暴力法更快?
因为双指针法只遍历柱状图一次,而暴力法需要遍历柱状图中的每个矩形。 - 双指针法可以处理负数高度吗?
不可以,因为算法假设柱状图中所有高度都是非负数。 - 算法是否可以处理有重复高度的柱状图?
是的,算法可以处理重复高度的情况。 - 算法是否可以在线处理输入?
是的,双指针法可以在线处理输入,即在接收新高度时逐步更新最大面积。 - 算法是否可以推广到三维空间?
是的,可以将算法推广到三维空间中,但需要使用更复杂的数据结构和计算方法。
总结
寻找柱状图中的最大矩形面积是一个经典的算法问题,它考验着我们的算法思维和优化技巧。本文从直观的暴力法到优雅的双指针法,深入探讨了多种解决方法,带领读者领略算法之美。在不断钻研和优化算法的过程中,我们不仅提高了编程技能,更培养了缜密的思维和对解决问题的热情。