返回

递增队列问题 - LeetCode 862. Shortest Subarray with Sum at Least K 题解

闲谈

我们都有一个共同的目标,就是要解决一个具有挑战性的问题:在给定的数组中找到满足总和小于 K 的最短子数组。当你想说,这是一件容易的事,就记住,它被标记为一个中等难度的问题。不过,别担心,因为它根本不是一个难题。

考虑一个更简单的例子,一个由 7 个整数构成的数组:[1, 2, 3, 4, 5, 6, 7],设定的目标总和为 15。这个数组中的子数组有许多种,为了节省时间,我假设只有两个最短的满足条件:

[1, 2, 3, 4, 5](和为 15[2, 3, 4, 5, 6](和为 20

现在,我们对问题本身进行更好的概括。给定一个数组 nums 和一个整数 k,我们需要找到最短的连续子数组,其元素之和等于或大于 k。当数组为空时,我们返回 0。这是一个经典的滑动窗口问题。

解决这个问题的一个更优的方法是使用递增队列。简单地说,递增队列是一个 FIFO(先进先出)的数据结构,其中元素按非递减顺序排序。这意味着队列中的第一个元素始终是最小的。

为了更好地理解它的工作原理,让我们看看它是如何解决这个问题的:

1.	我们将递增队列初始化为空。
2.	我们从数组开头开始,并遍历整个数组。
3.	对于数组中的每个元素,我们检查队列是否为空。如果是,我们直接将元素放入队列中。如果不是,我们比较当前元素和队列末尾的元素。
4.	如果当前元素大于或等于队列末尾的元素,我们将队列末尾的元素出队,然后将当前元素入队。
5.	我们继续比较当前元素和队列末尾的元素,直到它们相等或当前元素小于队列末尾的元素。
6.	一旦我们找到一个元素使队列末尾的元素大于或等于当前元素,我们计算从队列开头到当前元素的总和。如果总和大于或等于 k,我们更新最小长度并记录子数组的起始和结束索引。
7.	我们从队列中移除第一个元素并重复从第 3 步开始,直到我们到达数组末尾。

现在,让我们用代码来实现这个算法。我们使用 Python 语言编写代码,以便您能够轻松地理解和运行它。

def shortest_subarray(nums, k):
    """
    :type nums: List[int]
    :type k: int
    :rtype: int
    """
    # 初始化递增队列和最短长度
    queue = []
    min_len = float('inf')

    # 从数组开头开始,遍历整个数组
    for i, num in enumerate(nums):
        # 将元素放入队列
        while queue and queue[-1] > num:
            queue.pop()
        queue.append(num)

        # 计算总和并更新最短长度
        total = 0
        for j in range(len(queue)):
            total += queue[j]
            if total >= k:
                min_len = min(min_len, i - j + 1)
                break

    # 如果没有找到满足条件的子数组,返回 0
    return min_len if min_len != float('inf') else 0


# 测试代码
nums = [1, 2, 3, 4, 5, 6, 7]
k = 15
result = shortest_subarray(nums, k)
print(result)  # 输出:5

希望这份题解能够帮助你理解这个算法并解决这个问题。如果你有任何问题或建议,请随时在评论区留言。