📜  带有丑陋数字的子数组的最大长度(1)

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

带有丑陋数字的子数组的最大长度

问题描述

给定一个整数数组 nums,请找到其中最长的子数组,其数字中的最大值和最小值的差值不超过任意给定的丑陋数字 k

解决方法

为了解决这个问题,我们可以使用滑动窗口来找到其中最长的子数组。

具体来说,我们可以维护两个指针 leftright,分别表示窗口的左右边界,然后我们可以在一次遍历中不断移动右指针 right,直到找到一个符合条件的子数组为止。在移动右指针的过程中,我们需要维护一个变量 min_val 表示当前窗口中的最小值,以及一个变量 max_val 表示当前窗口中的最大值,如果 max_val - min_val 大于丑陋数字 k,则我们需要移动左指针 left,直到窗口符合条件为止。

在移动左指针的过程中,我们可以使用一个变量 min_idx 记录当前窗口中最小值的下标,以及一个变量 max_idx 记录当前窗口中最大值的下标。当 left 移动之后,如果 min_idx 或者 max_idx 等于 left,则我们需要重新找到窗口中的最小值或者最大值,并更新 min_idx 或者 max_idx

为了方便计算,我们可以使用两个单调队列 max_qmin_q 来维护窗口中的最大值和最小值,其中 max_q 是一个单调递减的队列,存储当前窗口中的最大值,min_q 是一个单调递增的队列,存储当前窗口中的最小值。每次移动右指针 right 的时候,我们可以把新的元素加入队列 max_qmin_q 中,并且在加入之前把队列中大于等于当前元素的部分弹出。每次移动左指针 left 的时候,我们可以把队列 max_qmin_q 中队首下标等于 left 的元素弹出。

最后,我们可以计算窗口的长度,如果长度大于之前找到的最大长度,则我们更新最大长度。

参考代码

下面是参考代码实现,其中 max_qmin_q 分别表示单调队列。由于需要返回最大长度,因此我们可以在更新最大长度的时候同时更新窗口的左右边界。代码中用 res_lres_r 分别表示当前找到的最长子数组的左右边界。

def max_length(nums, k):
    n = len(nums)
    max_q, min_q = [], []
    left, right, res_l, res_r = 0, 0, 0, 0

    for right in range(n):
        while max_q and nums[right] > nums[max_q[-1]]:
            max_q.pop()
        while min_q and nums[right] < nums[min_q[-1]]:
            min_q.pop()
        max_q.append(right)
        min_q.append(right)

        while nums[max_q[0]] - nums[min_q[0]] > k:
            left += 1
            if max_q[0] < left:
                max_q.pop(0)
            if min_q[0] < left:
                min_q.pop(0)

        if right - left + 1 > res_r - res_l + 1:
            res_l, res_r = left, right

    return res_r - res_l + 1
复杂度分析

代码中用一个单调队列来维护窗口中的最大值和最小值,因此时间复杂度为 $O(n)$。空间复杂度为 $O(n)$,因为最坏情况下窗口可能会扩展到长度为 $n$。