📌  相关文章
📜  最长子数组,以使max和min之差最大为1(1)

📅  最后修改于: 2023-12-03 15:26:28.639000             🧑  作者: Mango

最长子数组,以使max和min之差最大为1

题意

给定一个长度为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),需要良好的思维能力和代码实现能力。