📌  相关文章
📜  大小大于K且总和大于给定值的最小子数组(1)

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

题目介绍

给定一个大小为 $n$ 的正整数序列 $a$,以及正整数 $K$ 和 $S$,求最短的子数组 $b_{i},b_{i+1},\cdots,b_{j}$,使得 $b_{i}+b_{i+1}+\cdots+b_{j} \geq S$ 且 $j-i+1 \geq K$ 成立。若不存在这样的子数组,输出 $-1$。

解题思路

首先,我们可以把给定的序列 $a$ 变成一个前缀和数组 $s$,即 $s_{i}=a_{1}+a_{2}+\cdots+a_{i}$。那么题目中的子数组就可以转化为前缀和数组中的两个下标的差值。

接下来,考虑如何找到长度 $\geq K$ 且和 $\geq S$ 的最短子数组。我们可以从前向后遍历前缀和数组 $s$,对于每个位置 $i$,我们要找到其中一个最早出现的位置 $j$,使得 $s_{j}-s_{i-1} \geq S$ 且 $j-i+1 \geq K$,则该子数组就是长度 $\geq K$ 且和 $\geq S$ 的最短子数组。

为了找到最小的子数组,我们可以使用双指针法。具体地,我们初始化两个指针 $l$ 和 $r$,均指向前缀和数组的起始位置。然后,我们不断移动指针 $r$,直到找到一个位置满足 $s_{r}-s_{l-1} \geq S$ 且 $r-l+1 \geq K$。这时,我们记录当前子数组的长度 $r-l+1$,然后尝试将指针 $l$ 右移。如果子数组的长度仍然 $\geq K$,则我们尝试将指针 $l$ 右移,直到新的子数组不满足条件。重复这个过程,直到我们找到一个最小的子数组。

代码实现

下面给出使用 Python 语言实现的代码,时间复杂度为 $O(n)$:

def smallest_subarray(nums, k, s):
    n = len(nums)
    if k > n:
        return -1

    # 计算前缀和数组
    prefix_sum = [0] * (n + 1)
    for i in range(1, n + 1):
        prefix_sum[i] = prefix_sum[i - 1] + nums[i - 1]

    # 初始化双指针
    left = 1
    right = k
    min_len = n + 1

    # 滑动窗口
    while right <= n:
        if prefix_sum[right] - prefix_sum[left - 1] >= s:
            # 当前子数组满足条件
            min_len = min(min_len, right - left + 1)
            left += 1
        else:
            # 当前子数组不满足条件
            right += 1

    return -1 if min_len == n + 1 else min_len

其中,输入参数 nums 是一个大小为 $n$ 的正整数序列,输入参数 ks 分别表示子数组的最小长度和最小总和。返回值为最短子数组的长度,若不存在这样的子数组则返回 $-1$。