📅  最后修改于: 2023-12-03 15:26:28.639000             🧑  作者: Mango
给定一个长度为n的整数数组,找出其中的一个最长子数组,使得该子数组中的最大值与最小值的差为1。
我们可以尝试枚举每个子数组,检查它们的最大值和最小值之差是否为1。时间复杂度为O(n^3),无法通过LeetCode。
优化1:我们可以用两个指针,一个指向子数组的开始,另一个指向子数组的结束。每次移动结束指针,向右扩展子数组,并在扩展时实时更新最大值和最小值。如果最大值和最小值之差为1,更新答案。时间复杂度为O(n^2),可以通过LeetCode,但是不是最优解。
优化2:我们可以用两个单调栈,分别记录当前值向左/右跳的最远距离。这样,对于一个子数组,最大值和最小值的位置一定在这两个单调栈中间。我们可以枚举所有的值作为最大值或最小值,计算当前答案。时间复杂度为O(n),是最优解。
以下是优化2的代码:
class Solution:
def findLength(self, nums: List[int]) -> int:
n = len(nums)
# 计算左侧单调栈
left = [0] * n
stack = []
for i in range(n):
while stack and nums[stack[-1]] > nums[i]:
stack.pop()
left[i] = -1 if not stack else stack[-1]
stack.append(i)
# 计算右侧单调栈
right = [0] * n
stack = []
for i in range(n - 1, -1, -1):
while stack and nums[stack[-1]] > nums[i]:
stack.pop()
right[i] = n if not stack else stack[-1]
stack.append(i)
# 枚举最大值和最小值
ans = 0
for i in range(n):
for j in (i + 1, i - 1):
if 0 <= j < n and abs(nums[i] - nums[j]) == 1:
ans = max(ans, right[i] - left[j] - 1)
return ans
这道题考察了双指针、单调栈和枚举思想。最优解的时间复杂度为O(n),需要良好的思维能力和代码实现能力。